Các quy trình ứng dụng trên Android không tồn tại độc lập. Các ứng dụng thường dựa vào các dịch vụ do các ứng dụng khác hoặc chính hệ thống cung cấp. Khi một quy trình kết nối với một quy trình khác thông qua Service Binding (Liên kết dịch vụ), quy trình đó sẽ tạo ra một phần phụ thuộc có ảnh hưởng sâu sắc đến cách khung Android quản lý bộ nhớ.
Trạng thái quy trình và điểm OOM
Khung Android sử dụng Trạng thái quy trình để theo dõi mức độ quan trọng của từng quy trình đang chạy. Sau đó, OomAdjuster sẽ dùng các trạng thái này để chỉ định giá trị Mức điều chỉnh điểm OOM (oom_score_adj), trong khoảng từ -1000 đến 1000.
oom_score_adj thấp hơn có nghĩa là quy trình quan trọng hơn và ít có khả năng bị Low Memory Killer (LMK) dừng hơn.
Các trạng thái quy trình phổ biến
Bảng sau đây cho thấy một số trạng thái quy trình phổ biến nhất và các giá trị oom_score_adj điển hình của trạng thái đó. Để xem danh sách đầy đủ và mới nhất, hãy tham khảo android.app.ActivityManager và com.android.server.am.psc.Constants trong mã nguồn Android.
| Trạng thái quy trình (viết tắt) | Mô tả | oom_score_adj thông thường |
|---|---|---|
| PER (Cố định) | Các quy trình hệ thống luôn phải chạy (ví dụ: Điện thoại). | -800 |
| TOP | Quy trình mà người dùng hiện đang tương tác. | 0 |
| VIS (Visible) | Quá trình này có một hoạt động hiển thị (ví dụ: phía sau một hộp thoại mờ). | 100 |
| PERC (Có thể nhận thấy) | Quy trình chạy trong nền mà người dùng biết (ví dụ: phát nhạc). | 200 |
| FGS | Quy trình lưu trữ một Dịch vụ trên nền trước. | 0 đến 200 (tuỳ theo) |
| BTOP (Bound Top) | Quy trình bị ràng buộc bởi một ứng dụng TOP. | 100 |
| BFGS | Dịch vụ trên nền trước được liên kết (thường là được liên kết với hệ thống). | 0 |
| PREV (Trước) | Quy trình cuối cùng mà người dùng đã thực hiện trước quy trình hiện tại. | 700 |
| CACHED | Các ứng dụng nền có thể bị loại bỏ một cách an toàn. | 900 đến 999 |
Tác động của các liên kết dịch vụ
Khi một quy trình ứng dụng (ví dụ: một ứng dụng ở trạng thái TOP) liên kết với một dịch vụ trong quy trình máy chủ, quy trình máy chủ thường kế thừa mức độ ưu tiên cao. Điều này đảm bảo rằng dịch vụ vẫn hoạt động miễn là ứng dụng cần.

Kiểm soát việc kế thừa bằng cờ BIND
Tính kế thừa là hành vi mặc định khi sử dụng Context.BIND_AUTO_CREATE.
Tuy nhiên, nhà phát triển có thể kiểm soát cách liên kết ảnh hưởng đến tầm quan trọng của quy trình đích bằng nhiều cờ trong bindService().
Các cờ BIND chính cho điểm OOM
Các cờ sau đây phù hợp nhất khi quản lý áp lực bộ nhớ trên toàn hệ thống:
BIND_AUTO_CREATE: Cờ phổ biến nhất. Điều này đảm bảo quy trình dịch vụ được bắt đầu và duy trì hoạt động miễn là có liên kết. Theo mặc định, ứng dụng này cũng nâng cao mức độ ưu tiên của quy trình máy chủ để phù hợp với ứng dụng.BIND_NOT_FOREGROUND: Ngăn quy trình của dịch vụ mục tiêu được nâng lên mức ưu tiên lập lịch trên nền trước (mức ưu tiên CPU). Tuy nhiên, điều này vẫn cho phép tăng mức độ ưu tiên bộ nhớ (oom_score_adj). Điều này hữu ích cho những tác vụ ở chế độ nền không nên cạnh tranh với giao diện người dùng để giành chu kỳ CPU nhưng vẫn phải được bảo vệ khỏi bị chấm dứt.BIND_WAIVE_PRIORITY: Một cờ rất mạnh hướng dẫn hệ thống không ảnh hưởng đến mức độ ưu tiên lập lịch hoặc quản lý bộ nhớ của quy trình đích. Quy trình dịch vụ sẽ được quản lý như thể đó là một quy trình nền thông thường trong danh sách LRU, khiến quy trình này đủ điều kiện để bị loại bỏ do hết bộ nhớ ngay cả khi được liên kết.BIND_ABOVE_CLIENT: Cho biết dịch vụ này quan trọng hơn chính ứng dụng khách. Khi cần thu hồi bộ nhớ, hệ thống sẽ ưu tiên huỷ ứng dụng khách trước khi huỷ dịch vụ ràng buộc. Điều này "mạnh mẽ" hơnBIND_AUTO_CREATEvì nó cung cấp thêm một lớp bảo vệ cho dịch vụ, nhưng lại gây bất tiện cho máy khách.BIND_NOT_PERCEPTIBLE: Giảm mức độ quan trọng của dịch vụ mục tiêu xuống dưới cấpPERCEPTIBLE, cho phép hệ thống thu hồi bộ nhớ để nhường chỗ cho các quy trình quan trọng hơn mà người dùng có thể nhận thấy.
Thực hành: quan sát các hiệu ứng liên kết
Chúng ta sẽ sử dụng ứng dụng MemoryLab để minh hoạ cách một liên kết từ ứng dụng TOP ảnh hưởng đến trạng thái của một quy trình riêng biệt.
1. Khởi chạy MemoryLab
Lệnh sau sẽ khởi chạy ứng dụng. Sau khi ứng dụng mở, hãy đảm bảo ứng dụng vẫn ở nền trước (chưa nhấn nút Trang chủ hoặc chuyển đổi ứng dụng).
adb shell am start -n com.android.memorylab/.MainActivity
2. Xác định quy trình
Kiểm tra trạng thái của quy trình trước khi liên kết. MemoryLab chạy giao diện người dùng chính trong một quy trình và có một RemoteService chạy trong quy trình :remote.
adb shell dumpsys activity processes com.android.memorylab
Đoạn mã đầu ra mẫu:
Process OOM control (154 total, non-act at 7, non-svc at 7):
Proc #0: fg T/A/TOP LCMNFUATI t: 0 13470:com.android.memorylab/u0a417 (top-activity)
oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
state: cur=TOP set=TOP lastRss=0.00 lastCachedRss=0.00
Bạn sẽ thấy quy trình chính com.android.memorylab ở trạng thái TOP. Quy trình :remote chưa bắt đầu.
3. Liên kết điều kiện kích hoạt
Gửi một thông báo truyền tin đến ứng dụng để kích hoạt việc liên kết dịch vụ:
adb shell am broadcast -a com.android.memorylab.LEAK_BINDER
4. Quan sát trạng thái nâng cao
Kiểm tra lại trạng thái của quy trình:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Đoạn mã đầu ra mẫu:
Proc # 1: vis F/ /BTOP ---NFUATI t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=100 setRaw=100 cur=100 set=100
state: cur=BTOP set=BTOP lastRss=0.00 lastCachedRss=0.00
Quy trình :remote hiện đang chạy và ở trạng thái BTOP (Bound TOP) với oom_score_adj là 100. Điều này được bảo vệ hơn đáng kể so với một dịch vụ nền thông thường (sẽ ở 500 trở lên). Ký hiệu <=Proc{...} cho biết quy trình nào chịu trách nhiệm cho việc nâng cao mức độ ưu tiên này.
5. Chuyển sang phát trong nền
Nhấn nút HOME (TRANG CHỦ) trên thiết bị. Kiểm tra lại các trạng thái:
adb shell dumpsys activity processes | grep -A 10 "com.android.memorylab"
Đoạn mã đầu ra mẫu:
Proc # 2: prev b/ /LAST --------I t: 0 13560:com.android.memorylab:remote/u0a417 (service)
com.android.memorylab/.RemoteService<=Proc{13470:com.android.memorylab/u0a417}
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=0.00 lastCachedRss=0.00
Proc # 1: prev b/ /LAST --------I t: 0 13470:com.android.memorylab/u0a417 (previous)
oom: max=1001 curRaw=700 setRaw=700 cur=700 set=700
state: cur=LAST set=LAST lastRss=209MB lastCachedRss=0.00
Giờ đây, cả hai quy trình đều đã chuyển sang trạng thái có mức độ ưu tiên thấp hơn (PREV / oom_score_adj 700), vì quy trình của ứng dụng khách không còn là TOP nữa. (Lưu ý: LAST trong kết xuất trạng thái đề cập đến trạng thái nội bộ LAST_ACTIVITY, được liên kết với PREV trong các bản tóm tắt cấp cao).
Phân tích bằng procstats
Công cụ procstats cung cấp chế độ xem nhật ký của các trạng thái này.
# View stats for MemoryLab over the last hour
adb shell dumpsys procstats --hours 1 com.android.memorylab
Đoạn mã đầu ra mẫu:
* com.android.memorylab / u0a417 / v37:
* Prc com.android.memorylab / u0a417 / v37:
TOTAL: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
Top: 0.89% (0.00-0.00-0.00/0.00-0.00-0.00/210MB-210MB-210MB over 1)
* Prc com.android.memorylab:remote / u0a417 / v37:
TOTAL: 0.19%
Bnd Top: 0.19%
Trong đó, Bnd Top cho biết tỷ lệ phần trăm thời gian mà quy trình từ xa đã dành để được một ứng dụng liên kết ở trạng thái TOP.
Ghi lại và phân tích các liên kết bằng Perfetto
Trong khi dumpsys cung cấp cho bạn thông tin tổng quan, Perfetto cho phép bạn xem chính xác thời điểm xảy ra một hoạt động liên kết và cách điểm OOM thay đổi theo thời gian thực.
1. Ghi lại dấu vết
Sử dụng cấu hình bao gồm linux.process_stats và danh mục am atrace:
adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/service_bindings.perfetto-trace <<EOF
buffers: { size_kb: 65536 }
data_sources: {
config {
name: "linux.process_stats"
process_stats_config { proc_stats_poll_ms: 100 }
}
}
data_sources: {
config {
name: "linux.ftrace"
ftrace_config { ftrace_events: "am/am_proc_bound" }
}
}
duration_ms: 15000
EOF
2. Chuyển đổi điểm OOM của truy vấn
Khi dùng PerfettoSQL, bạn có thể thấy điểm OOM của quy trình từ xa đã thay đổi như thế nào so với quy trình giao diện người dùng:
SELECT ts, p.name, value AS oom_score_adj
FROM counter c
JOIN process_counter_track t ON c.track_id = t.id
JOIN process p USING (upid)
WHERE p.name LIKE 'com.android.memorylab%'
AND t.name = 'oom_score_adj'
ORDER BY ts;
3. Xác định các sự kiện liên kết
Để biết chính xác thời điểm thiết lập một phần phụ thuộc liên kết và quy trình nào đã khởi tạo phần phụ thuộc đó, hãy sử dụng truy vấn này:
SELECT
s.ts,
p.name AS process_name,
t.name AS thread_name,
s.name AS slice_name
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE s.name LIKE 'bindService:{com.android.memorylab%';
Liên kết từ hệ thống đến ứng dụng
Bản thân hệ thống Android thường liên kết với các dịch vụ trong ứng dụng bên thứ ba để cung cấp chức năng cốt lõi. Mục tiêu của các liên kết này thường là giảm độ trễ. Bằng cách duy trì một quy trình đang hoạt động và trong bộ nhớ, hệ thống tránh được chi phí phát sinh lớn của quá trình "khởi động nguội" (tải APK, khởi động thời gian chạy và tạo đối tượng Ứng dụng) khi xảy ra một hoạt động tương tác quan trọng của người dùng. Các liên kết khác tồn tại để ngăn chặn việc khởi động nguội thường xuyên cho các ứng dụng cần xử lý luồng sự kiện nền.
Sau đây là một số ví dụ thực tế mà bạn có thể quan sát trên một thiết bị thông thường:
VoiceInteractor
Người dùng mong muốn có một trợ lý kỹ thuật số được nhúng trong hệ điều hành điện thoại của họ, có thể gọi trợ lý này ngay lập tức bằng một từ khoá kích hoạt bằng giọng nói hoặc một cử chỉ nhập nhanh, đồng thời có thể tương tác một cách mượt mà và liền mạch.
Khi có một cụm từ kích hoạt trợ lý (chẳng hạn như từ khoá kích hoạt "OK Google" trên điện thoại Google Pixel), trợ lý kỹ thuật số cần phản hồi ngay lập tức. Để đảm bảo điều này, system_server duy trì một mối liên kết vĩnh viễn với dịch vụ tương tác bằng giọng nói do người dùng chọn.

Nếu kiểm tra trạng thái của quy trình (ví dụ: bằng cách dùng dumpsys activity processes), bạn có thể thấy một quy trình như com.google.android.googlequicksearchbox:interactor ở trạng thái BFGS (Dịch vụ liên kết trên nền trước), được duy trì hoạt động bằng một liên kết từ system_server (UID 1000).
NotificationListenerService
Đối với một số liên kết từ hệ thống đến ứng dụng, mục tiêu không phải là độ trễ mà là ngăn chặn tình trạng khởi động nguội thường xuyên.
NotificationListenerService, một dịch vụ nhận các lệnh gọi từ hệ thống khi thông báo mới được đăng hoặc bị xoá, là một ví dụ điển hình. Một người dùng điện thoại thông minh thông thường có thể nhận được hàng trăm thông báo trong suốt cả ngày. Nếu hệ thống huỷ liên kết khỏi một trình nghe thông báo, thì quy trình của ứng dụng đó có thể chuyển sang trạng thái được lưu vào bộ nhớ đệm và có thể bị LMK huỷ.
Khi thông báo tiếp theo đến (có thể chỉ vài giây sau), hệ thống sẽ buộc phải khởi động nguội quy trình của ứng dụng một lần nữa chỉ để gửi sự kiện. Chu trình liên tục buộc tắt và khởi động lại này sẽ tiêu tốn nhiều CPU và pin hơn so với việc chỉ giữ cho quy trình được liên kết và hoạt động ở chế độ nền.
"Màn hình -1" (nguồn cấp dữ liệu tin tức) của trình chạy
Các ứng dụng Trình chạy hiện đại thường kết hợp chức năng điều hướng cốt lõi (các biểu tượng và tiện ích trên màn hình chính) với một nguồn cấp tin tức có trên một trong các màn hình trình chạy và được tích hợp liền mạch với Giao diện người dùng Trình chạy. Nguồn cấp tin tức có thể do một ứng dụng khác cung cấp. Ví dụ: trên Google Pixel, Trình chạy tích hợp với một nguồn cấp do ứng dụng Google cung cấp.
Khi bạn vuốt sang trái trên màn hình chính để xem nguồn cấp tin tức, hiệu ứng chuyển đổi phải mượt mà. Trình chạy đạt được điều này bằng cách liên kết với một giao diện dịch vụ trong ứng dụng cung cấp nguồn cấp tin tức và duy trì mối liên kết đó trong thời gian trình chạy hoạt động. Việc này giúp nội dung trong nguồn cấp dữ liệu được kết xuất và sẵn sàng trong bộ nhớ ngay cả khi bạn không xem.
Các ví dụ thường gặp khác
- Trình chạy (HOME_APP_ADJ): Ứng dụng trình chạy (Trang chủ) có một vị trí đặc biệt trong danh sách ưu tiên. Mặc dù không phải lúc nào cũng bị ràng buộc bởi một dịch vụ, nhưng nó được chỉ định
HOME_APP_ADJ(thường là 600). Hệ thống ưu tiên duy trì hoạt động của trình chạy, vì người dùng thường xuyên quay lại trình chạy này. Trên thực tế, hệ thống sẽ ưu tiên dừng ứng dụng đã dùng trước đó (PREV_APP_ADJ = 700) hơn là dừng trình chạy, vì việc dừng trình chạy sẽ khiến trải nghiệm người dùng trở nên chậm chạp khi thoát bất kỳ ứng dụng nào vì người dùng sẽ cần đợi trình chạy khởi động nguội. - Trình chỉnh sửa phương thức nhập (IME): Khi bạn nhập, hệ thống sẽ liên kết với ứng dụng bàn phím mà bạn chọn (ví dụ: Gboard). Điều này giúp duy trì quy trình bàn phím ở trạng thái nâng cao ngay cả khi bàn phím tạm thời bị ẩn. Điều này đảm bảo bàn phím có thể xuất hiện lại ngay lập tức khi bạn nhấn vào một trường văn bản khác.
- Thanh toán qua NFC: Khi bạn chạm điện thoại để thanh toán, hệ thống sẽ liên kết với dịch vụ thanh toán NFC (ví dụ: Google Wallet). Những giao dịch này thường có các yêu cầu nghiêm ngặt về thời gian thực từ thiết bị đầu cuối của người bán. Nếu ứng dụng thanh toán phải khởi động nguội, thì giao dịch có thể hết thời gian chờ và không thành công.
Những điểm lợi, hại và hiệu suất giảm đột ngột
Mặc dù các liên kết là cần thiết để đảm bảo hiệu suất và tính chính xác, nhưng chúng ảnh hưởng đến tình trạng bộ nhớ của hệ thống.
- Giảm tính linh hoạt: Mọi quy trình liên kết đều là quy trình mà LMK không dễ dàng loại bỏ. Điều này làm giảm "khoảng đệm" của các quy trình được lưu vào bộ nhớ đệm mà hệ thống có thể dùng để giải phóng bộ nhớ khi chịu áp lực.
- Làm trầm trọng thêm tình trạng suy giảm hiệu suất: Nếu có quá nhiều quy trình được liên kết, hệ thống có thể thấy rằng hầu như không có quy trình nào ở chế độ nền có thể bị loại bỏ. Khi áp lực về bộ nhớ tăng lên, hệ thống sẽ "giảm hiệu suất" nhanh hơn nhiều, vì hệ thống buộc phải loại bỏ các quy trình quan trọng hơn hoặc xoá bộ nhớ đệm trang.
Các mẫu chống liên kết dịch vụ phổ biến
Vì các liên kết dịch vụ trực tiếp nâng cao oom_score_adj, những lỗi nhỏ về vòng đời trong cách bạn thu thập hoặc cấu trúc các liên kết có thể ghim một lượng lớn bộ nhớ ở các trạng thái đặc quyền (BTOP, BFGS hoặc PERC) trong nhiều giờ. Hãy chú ý đến những mẫu chống phổ biến này khi thiết kế hoặc kiểm tra các dịch vụ liên kết.
Quên unbindService() trong các ứng dụng có thời gian tồn tại lâu dài
Việc liên kết với một dịch vụ từ một singleton Application, một trình quản lý nền hoặc một Activity gọi bindService() trong onStart() mà không có unbindService() tương ứng trong onStop() sẽ làm rò rỉ ServiceConnection.
Miễn là liên kết đó vẫn hoạt động, quy trình đích sẽ kế thừa mức độ ưu tiên cao của ứng dụng. Nếu ứng dụng là một thành phần hệ thống liên tục hoặc một ứng dụng trên nền trước, thì quy trình dịch vụ ràng buộc sẽ vẫn được ghim vô thời hạn trong BFGS hoặc BTOP (xuất hiện gần 100% trong procstats), ngăn LMK thu hồi bộ nhớ của ứng dụng ngay cả khi dịch vụ hoàn toàn không hoạt động.
Giải pháp: Liên kết phạm vi một cách nghiêm ngặt với vòng đời của thành phần cần các liên kết đó hoặc triển khai thời gian chờ ở trạng thái rảnh gọi unbindService() sau một khoảng thời gian không hoạt động. Tránh huỷ liên kết và liên kết lại trên mỗi lệnh gọi RPC riêng lẻ, điều này gây ra tình trạng đơ máy và lặp lại chi phí thiết lập Trình liên kết; thay vào đó, hãy kết hợp các đợt công việc sau một bộ hẹn giờ rảnh ngắn (ví dụ: 5 đến 30 giây).
Đồng định vị một dịch vụ ràng buộc với giao diện người dùng cần nhiều bộ nhớ
Theo mặc định, tất cả các thành phần trong một APK đều chạy trong cùng một quy trình. Nếu ứng dụng của bạn hiển thị một dịch vụ ràng buộc đơn giản (chẳng hạn như NotificationListenerService, một trình cung cấp tiện ích hoặc một dịch vụ bổ trợ mà hệ thống hoặc trình chạy liên kết đến) trong cùng một quy trình với Activity chính, thì toàn bộ quy trình sẽ kế thừa trạng thái nâng cao của dịch vụ (BFGS hoặc PERC, thường là oom_score_adj từ 200 trở xuống).
Khi người dùng mở giao diện người dùng của ứng dụng, quy trình này sẽ phân bổ các hệ phân cấp khung hiển thị lớn, bitmap đã giải mã và bộ đệm đồ hoạ. Khi người dùng chuyển ra khỏi ứng dụng, quy trình sẽ không giảm xuống CACHED (oom_score_adj từ 900 trở lên) vì hoạt động liên kết dịch vụ đang hoạt động sẽ giữ cho quy trình ở mức cao. Điều này gây ra hai vấn đề phức tạp:
- Không có tính năng nén bộ nhớ ở chế độ nền:
CachedAppOptimizercủa hệ thống chỉ nén các quy trình sau khi chúng chuyển sang trạng tháiCACHED. - Không có hoạt động cắt bớt bộ nhớ LRU được lưu vào bộ nhớ đệm hoặc thu hồi LMK: Hệ thống không phân phối các lệnh gọi lại cắt bớt ở chế độ nền được liên kết với danh sách LRU được lưu vào bộ nhớ đệm (
TRIM_MEMORY_BACKGROUNDtrở lên) trong khi một liên kết dịch vụ giữ quy trình ở trạng thái nâng cao. Nếu ứng dụng của bạn không giải phóng rõ ràng các tài nguyên giao diện người dùng trênTRIM_MEMORY_UI_HIDDENhoặcActivity.onStop(), thì các hoạt động phân bổ giao diện người dùng cao nhất sẽ vẫn được ghim trong RAM ở điểm OOM đặc quyền mà LMK không thể dễ dàng thu hồi.
Giải pháp: Xoá rõ ràng các bộ nhớ đệm giao diện người dùng, bitmap đã giải mã và các tham chiếu đến khung hiển thị khi giao diện người dùng của bạn ngừng hiển thị, bằng cách sử dụng Activity.onStop(), ComponentCallbacks2.onTrimMemory(TRIM_MEMORY_UI_HIDDEN), Application.ActivityLifecycleCallbacks hoặc ProcessLifecycleOwner. Ngoài ra, hãy di chuyển dịch vụ luôn liên kết vào một quy trình riêng biệt, gọn nhẹ bằng cách sử dụng thuộc tính tệp kê khai android:process để hệ thống có thể di chuyển quy trình giao diện người dùng chính của bạn vào trạng thái CACHED nhằm nén hoặc thu hồi bộ nhớ một cách độc lập.
Bỏ qua các cờ ưu tiên
Chỉ gọi bindService() bằng BIND_AUTO_CREATE sẽ chuyển toàn bộ lịch biểu và mức độ ưu tiên về bộ nhớ của người gọi đến dịch vụ đích. Khi một ứng dụng trên nền trước liên kết với một dịch vụ phân tích, ghi nhật ký hoặc tìm nạp trước ở chế độ nền chỉ bằng cách dùng BIND_AUTO_CREATE, ứng dụng đó vô tình chuyển worker ở chế độ nền đó thành BTOP.
Giải pháp: Khi liên kết với các dịch vụ phụ trợ hoặc dịch vụ nỗ lực tối đa không cần cùng mức bảo vệ như giao diện người dùng ở nền trước, hãy kết hợp BIND_AUTO_CREATE với BIND_WAIVE_PRIORITY, BIND_NOT_FOREGROUND hoặc BIND_NOT_PERCEPTIBLE để hệ thống vẫn có thể quản lý quy trình đích trên danh sách LRU được lưu vào bộ nhớ đệm.
← Địa phương | ↑ Lên | Toàn hệ thống →