Trình nền quản lý bộ nhớ

Android 17 trở lên hỗ trợ trình nền quản lý bộ nhớ (mmd), một trình nền hệ thống, xử lý cấu hình trình nền, các thông số có thể điều chỉnh và các tác vụ bảo trì ZRAM hoặc hoán đổi đang diễn ra.

Nền

Trước khi mmd ra mắt, các cấu hình ZRAM của Android bị phân mảnh và có khả năng tuỳ chỉnh hạn chế. mmd giải quyết vấn đề này bằng cách tập trung việc quản lý ZRAM, cho phép logic cấu hình phức tạp hơn và đơn giản hoá việc bổ sung các tính năng mới cũng như cải thiện cấu trúc. mmd cũng thiết lập sự tách biệt rõ ràng về các mối lo ngại giữa quy trình system_server dựa trên Java và việc quản lý bộ nhớ hoặc hoán đổi ở cấp độ hạt nhân.

Cấu trúc và hoạt động quản lý ZRAM

Khi quá trình khởi động hoàn tất (tức là khi sys.boot_completed=1), mmd_setup sẽ cố gắng định cấu hình ZRAM bằng các tham số đã chỉ định. Sau khi thiết lập ZRAM xong, hệ thống sẽ bật dịch vụ mmd để xử lý các tác vụ bảo trì đang diễn ra.

Với dự án mmd, các hoạt động bảo trì được khởi chạy từ system_server bằng cách gửi các yêu cầu Binder đến mmd bằng giao diện IMmd. mmd xử lý các tác vụ bảo trì như thực hiện ghi lại ZRAM, nén lại và ghi lại theo từng quy trình dựa trên công cụ chính sách nội bộ của riêng nó. Bạn có thể định cấu hình cả lịch biểu từ ActivityManagerService và chính sách bảo trì ZRAM bằng cách sử dụng các thuộc tính hệ thống.

Tích hợp máy chủ hệ thống (system_server)

Quy trình system_server dựa trên Java sẽ xác định thời điểm gọi mmd. Quy trình này tách các lần dọn dẹp bảo trì chung khỏi các hoạt động tối ưu hoá bộ nhớ theo từng ứng dụng được nhắm đến.

Bảo trì hậu xử lý thông thường

Việc duy trì ZRAM trên toàn cầu được điều khiển bởi ActivityManagerService bằng com.android.server.memory.ZramMaintenance.

zram-maintenance

Hình 1. Quy trình lập lịch bảo trì ZRAM.

  • Công cụ lập lịch: ZramMaintenance đăng ký một công việc định kỳ ở chế độ nền với JobScheduler của Android.
  • Các giới hạn đối với công việc: Để ngăn tình trạng kết xuất gián đoạn giao diện người dùng trên nền trước hoặc tình trạng tranh chấp CPU, công việc được định cấu hình rõ ràng bằng setRequiresDeviceIdle(true)setRequiresBatteryNotLow(true).
  • Kích hoạt liên kết: Khi trình lập lịch kích hoạt onStartJob(), system_server sẽ gọi mmd.doZramMaintenanceAsync(). Đây là lệnh gọi Binder không đồng bộ một chiều; system_server không chặn chờ các lần quét bảo trì hoàn tất. mmd xếp hàng đợi này vào một luồng trình chạy trong nền để thực hiện việc nén lại và ghi lại tuần tự.

Ghi lại theo quy trình

ActivityManagerService quản lý việc loại bỏ bộ nhớ theo từng quy trình bằng cách sử dụng com.android.server.am.CachedAppOptimizer.

mmd-writeback

Hình 2. Quy trình ghi lại mmd cho mỗi quy trình.

Khi một quy trình chuyển sang trạng thái đã lưu vào bộ nhớ đệm ở chế độ nền, ActivityManager sẽ thực hiện việc nén bộ nhớ. Nếu người dùng có thể thấy lỗi tắt ứng dụng khi bộ nhớ thấp của quy trình, tức là quy trình lưu trữ một Hoạt động và nếu tính năng ghi lại ZRAM cho mỗi quy trình sẽ đưa mức sử dụng bộ nhớ của quy trình về gần bằng 0, thì hệ thống sẽ làm theo các bước sau:

  1. Sau khi nén, CachedAppOptimizer sẽ đăng một thông báo bị trì hoãn (ZRAM_WRITEBACK_MSG) cho trình xử lý nén nội bộ (bị trì hoãn bởi mZramWritebackWaitSeconds).
  2. Khi độ trễ hết hạn, ActivityManager sẽ mở một bộ mô tả tệp quy trình bảo mật pidfd.
  3. Máy chủ hệ thống gọi mmd.asyncWritebackProcessZramMemory(pfd, callback).
  4. mmd thực thi ioctl ghi lại theo quy trình và báo cáo lại bằng IMmdProcessWritebackCallback. Nếu thành công, ActivityManager sẽ gắn cờ bản ghi quy trình (setIsZramWrittenBack(app, true)) để tăng oom_score_adj của quy trình và ghi lại các chỉ số vào FrameworkStatsLog.ZRAM_WRITEBACK_EVENT.

Tìm nạp trước theo quy trình

Khi người dùng chạy lại một ứng dụng đã được lưu vào bộ nhớ đệm trước đó (được rã đông do UNFREEZE_REASON_ACTIVITY), ActivityManager sẽ giảm thiểu độ trễ khi khởi động ứng dụng do các lỗi trang chính từ bộ nhớ dự phòng:

  1. CachedAppOptimizer chặn sự kiện unfreeze và gọi prefetchZram(app).
  2. Máy chủ hệ thống gửi pidfd của ứng dụng trên Binder bằng cách sử dụng mmd.asyncPrefetchProcessZramMemory(pfd). mmd phát hành ioctl ZRAM_ANDROID_IOC_PROCESS_PREFETCH, hướng dẫn hạt nhân không đồng bộ tìm nạp trước các trang đã hoán đổi trở lại RAM trong khi luồng giao diện người dùng chính của ứng dụng đang khởi tạo.

Tổng quan về các công việc bảo trì và xử lý hậu kỳ

Phần này mô tả các hoạt động bảo trì trong nền và các tác vụ xử lý hậu kỳ mà mmd chạy để tối ưu hoá không gian trao đổi và bộ nhớ hệ thống.

Bảo trì trong mmd

Trong mmd, hoạt động bảo trì đề cập đến các hoạt động quét bảo trì theo lịch ở chế độ nền nhằm tối ưu hoá việc sử dụng không gian trao đổi và bộ nhớ vật lý mà không ảnh hưởng đến hiệu suất ở nền trước của người dùng đang hoạt động. Thay vì thực hiện các lượt quét đồng bộ, liên tục (gây ra tình trạng đánh thức CPU nghiêm trọng và giao diện người dùng bị giật), hoạt động duy trì được thực hiện không đồng bộ:

  1. system_server định kỳ kích hoạt doZramMaintenanceAsync() trên Binder.

  2. mmd đặt yêu cầu vào hàng đợi công việc trong nền LowPrioWorkItem::ZramMaintenance.

  3. Có một luồng worker duy nhất trong mmd, quản lý cả hàng đợi có mức độ ưu tiên cao và hàng đợi có mức độ ưu tiên thấp. Các mục công việc có mức độ ưu tiên cao (chẳng hạn như tìm nạp trước theo quy trình) sẽ được xử lý trước và có thể chiếm quyền xử lý các mục công việc có mức độ ưu tiên thấp. Việc bảo trì và ghi lại theo quy trình hoạt động dưới dạng các mục công việc có mức độ ưu tiên thấp. Khi được bật, luồng worker sẽ thực thi tuần tự 2 thao tác bảo trì chính:

    • Nén lại ZRAM: Quét các trang trao đổi hiện có và nén lại các trang không hoạt động bằng thuật toán nén thứ cấp có tỷ lệ cao hơn, ví dụ: zstd.

    • Ghi lại ZRAM: Quét các trang không hoạt động và loại bỏ hoàn toàn các trang đó khỏi RAM vào bộ nhớ flash dự phòng, một thiết bị vòng lặp từ một tệp trên /data.

Các tác vụ xử lý hậu kỳ trong ZRAM

Trong mô-đun ZRAM của nhân Linux và cấu trúc mmd, các tác vụ xử lý hậu kỳ là những biến đổi không đồng bộ được áp dụng cho các trang bộ nhớ sau khi chúng đã được hoán đổi bởi các đường dẫn thu hồi tiêu chuẩn của nhân (kswapd hoặc nén).

Khi một trang ban đầu được hoán đổi, hệ thống sẽ ưu tiên tốc độ: hệ thống sử dụng một thuật toán nén chính nhanh (chẳng hạn như lz4) và lưu trữ trang đã nén trong RAM. Tuy nhiên, theo thời gian, nhiều trang được hoán đổi sẽ trở nên lạnh hoặc không hoạt động, chẳng hạn như các ứng dụng được lưu vào bộ nhớ đệm ở chế độ nền không được tiếp tục trong nhiều giờ. Việc để các trang không hoạt động trong ZRAM nhanh, được nén nhẹ là không hiệu quả.

Quy trình hậu xử lý

mmd triển khai một vòng đời xử lý hậu kỳ nhiều giai đoạn để tối ưu hoá các trang này:

mmd-page-lifecycle

Hình 3. vòng đời của trang mmd.

  1. Giai đoạn 1: Hoán đổi ban đầu (nén nhanh): Bộ nhớ được thu hồi trước thông qua kswapd hoặc tính năng nén ứng dụng. Thông thường, lần thu hồi đầu tiên này được thực hiện bằng cách sử dụng một thuật toán nén nhanh như lz4 và nội dung được lưu trữ trong RAM.

  2. Giai đoạn 2: Đánh dấu trạng thái rảnh (lão hoá và theo dõi): mmd hoạt động theo dõi trạng thái rảnh truy cập vào tính năng theo dõi bộ nhớ kernel (CONFIG_ZRAM_TRACK_ENTRY_ACTIME) hoặc sử dụng điểm đánh dấu trạng thái rảnh của phần mềm để theo dõi thời gian các trang không được truy cập.

  3. Giai đoạn 3: Xử lý hậu kỳ 1 – nén lại (thu hồi trong bộ nhớ): Những trang đạt đến độ tuổi nén lại khi không hoạt động (min_idle_seconds đến max_idle_seconds) sẽ được nén lại. mmd ghi vào /sys/block/zram0/recompress để hướng dẫn hạt nhân giải nén trang lz4 và nén lại bằng zstd. Thao tác này sẽ giải phóng RAM vật lý mà không làm giảm tuổi thọ của bộ nhớ flash.

  4. Giai đoạn 4: Xử lý hậu kỳ 2 – ghi lại (loại bỏ vào bộ nhớ flash): Nếu áp lực bộ nhớ tiếp tục và các trang đạt đến độ tuổi ghi lại ở trạng thái rảnh (thường là 20 giờ trở lên), mmd sẽ kích hoạt quá trình ghi lại. mmd ghi vào /sys/block/zram0/idle/sys/block/zram0/writeback để hoàn toàn loại bỏ trang đã nén khỏi RAM vào bộ nhớ flash dự phòng.

Cấu hình thiết lập ZRAM

mmd tải và xử lý các thuộc tính thiết lập ZRAM sau đây:

Thuộc tính Sử dụng Mặc định
mmd.zram.enabled Thiết lập mmd ZRAM có được bật hay không. false
mmd.zram.num_devices Số lượng thiết bị ZRAM cần định cấu hình. Đối với một số N, các thiết bị zram0 đến zram<N-1> phải có mặt trước khi hệ thống đặt sys.boot_completed=1. Bạn có thể định cấu hình các thuộc tính trong danh sách thiết bị ZRAM theo từng thiết bị. 1
mmd.zram.device_priority Các giá trị ưu tiên cần truyền khi gọi swapon. Chưa đặt
mmd.zram.comp_algorithm Thuật toán nén ZRAM. Thuật toán nén mặc định của nhân được dùng nếu bạn không chỉ định. Chưa đặt
mmd.zram.size Kích thước thiết bị zRAM tính bằng byte hoặc tỷ lệ phần trăm kích thước RAM của thiết bị, ví dụ: 75%. 50%
mmd.zram.writeback.enabled Có bật tính năng ghi lại ZRAM hay không. false
mmd.zram.writeback.device_size Kích thước của thiết bị ghi lại tính bằng byte hoặc tỷ lệ phần trăm của phân vùng dữ liệu. Bạn có thể điều chỉnh kích thước thực tế của thiết bị dựa trên dung lượng có sẵn trên phân vùng dữ liệu. 1073741824 (1 GiB)
mmd.zram.writeback.min_free_space_mib Dung lượng trống tối thiểu (tính bằng MiB) cần có sau khi thiết lập thiết bị ghi lại. 1536 (1,5 GiB)
mmd.zram.writeback.use_nr_tags_prop Khi true, hãy sử dụng giá trị trong mmd.zram.writeback.nr_tags để định cấu hình độ sâu hàng đợi của tính năng ghi lại ZRAM hỗ trợ thiết bị vòng lặp. Đây là giải pháp cho những trường hợp không thể định cấu hình chính sách SELinux của nhà cung cấp để cho phép mmd trực tiếp đọc nr_tags của thiết bị chặn hỗ trợ /data. false
mmd.zram.writeback.nr_tags Vui lòng xem mmd.zram.writeback.use_nr_tags_prop. Chưa đặt
mmd.zram.recompression.enabled Có bật tính năng nén lại ZRAM hay không. false
mmd.zram.recompression.algorithm Thuật toán nén lại ZRAM thứ cấp. zstd

Thuộc tính thiết bị trên mỗi ZRAM

Khi mmd.zram.num_devices lớn hơn 1, bạn có thể tuỳ ý định cấu hình các thuộc tính cụ thể trên cơ sở mỗi thiết bị ZRAM bằng cách đặt thuộc tính thành một giá trị được phân tách bằng dấu phẩy chứa chính xác mmd.zram.num_devices phần tử. Các thuộc tính này bao gồm:

  • mmd.zram.size
  • mmd.zram.comp_algorithm
  • mmd.zram.device_priority
  • mmd.zram.recompression.enabled
  • mmd.zram.recompression.huge_idle.enabled
  • mmd.zram.recompression.idle.enabled
  • mmd.zram.recompression.huge.enabled
  • mmd.zram.recompression.threshold_bytes
  • mmd.zram.recompression.algorithm
  • mmd.zram.writeback.device_size
  • mmd.zram.writeback.huge_idle.enabled
  • mmd.zram.writeback.idle.enabled
  • mmd.zram.writeback.huge.enabled

Ngừng sử dụng chế độ thiết lập ZRAM hiện có

Mặc dù swapon_all vẫn có trên Android để thiết lập ZRAM và không gian trao đổi dựa trên đĩa, nhưng mmd là phương pháp ưu tiên để quản lý ZRAM nhằm giúp việc định cấu hình trở nên dễ dàng hơn và có các tính năng nâng cao như nén lại ZRAM.

Khi chế độ thiết lập mmd ZRAM được bật bằng mmd.zram.enabled:

  • Việc thiết lập ZRAM trong quá trình triển khai swapon_all sẽ không có tác dụng.
  • Các cấu hình ZRAM hiện có, chẳng hạn như config_zramWriteback trong tệp lớp phủ config.xml và các thuộc tính hệ thống ghi lại ro.zram.* sẽ bị bỏ qua.

Các thông số có thể điều chỉnh để bảo trì ZRAM

Việc duy trì ZRAM sẽ hoạt động ngay khi xuất xưởng và bạn có thể tinh chỉnh thêm bằng cách sử dụng các thuộc tính hệ thống trong phần này.

Lập lịch bảo trì ZRAM

Các thuộc tính này kiểm soát cách thức và thời điểm system_server lên lịch các tác vụ bảo trì ZRAM.

Thuộc tính Sử dụng Mặc định
mm.zram.maintenance.first_delay_seconds Độ trễ trước khi quá trình bảo trì ZRAM đầu tiên bắt đầu. 3600 (1 giờ)
mm.zram.maintenance.periodic_delay_seconds Độ trễ giữa các lần lập lịch bảo trì ZRAM tiếp theo. 3600 (1 giờ)
mm.zram.maintenance.require_device_idle Có nên chỉ bắt đầu bảo trì ZRAM khi thiết bị không hoạt động hay không. true
mm.zram.maintenance.require_battery_not_low Có cần yêu cầu pin không yếu trước khi bắt đầu bảo trì ZRAM hay không. true

Chính sách ghi lại ZRAM

Các tham số sau đây kiểm soát thời điểm và loại bộ nhớ được ghi vào thiết bị hỗ trợ:

Thuộc tính Sử dụng Mặc định
mmd.zram.writeback.backoff_seconds Thời gian tạm ngưng kể từ thao tác ghi lại gần đây nhất. 600 (10 phút)
mmd.zram.writeback.min_idle_seconds Kết hợp với mmd.zram.writeback.max_idle_seconds để tính toán thời gian không hoạt động của một trang để đủ điều kiện ghi lại dựa trên tỷ lệ sử dụng bộ nhớ. Tuổi không hoạt động được tính toán bằng cách nội suy theo hàm mũ giữa hai tham số để giảm thiểu công việc trong khi không chịu áp lực về bộ nhớ. 72000 (20 giờ)
mmd.zram.writeback.max_idle_seconds Số giây tối đa được dùng để tính toán động tuổi của trang không hoạt động dựa trên mức sử dụng bộ nhớ. 90000 (25 giờ)
mmd.zram.writeback.huge.enabled Có bật tính năng ghi lại trang HUGE hay không. false
mmd.zram.writeback.idle.enabled Có bật tính năng ghi lại trang IDLE hay không. true
mmd.zram.writeback.huge_idle.enabled Có bật tính năng ghi lại trang HUGE_IDLE hay không. true
mmd.zram.writeback.min_bytes Số byte tối thiểu cần ghi lại trong một vòng ghi lại ở trạng thái rảnh. 5242880 (5 MiB)
mmd.zram.writeback.max_bytes Số byte tối đa cần ghi lại trong một vòng ghi lại khi không hoạt động. 314572800 (300 MiB)
mmd.zram.writeback.max_bytes_per_day Số byte tối đa cần ghi lại trong khoảng thời gian 24 giờ. 25769803776 (24 GiB)
mmd.zram.writeback.limit.enabled Có bật tính năng kế toán giới hạn ngân sách ghi lại hằng ngày hay không. true

Chính sách nén lại ZRAM

Các tham số sau đây kiểm soát thời điểm và loại bộ nhớ được nén lại:

Thuộc tính Sử dụng Mặc định
mmd.zram.recompression.backoff_seconds Thời gian chờ kể từ lần nén lại gần đây nhất. 1800 (30 phút)
mmd.zram.recompression.min_idle_seconds Kết hợp với mmd.zram.recompression.max_idle_seconds để tính toán thời gian không hoạt động của một trang để đủ điều kiện nén lại dựa trên tỷ lệ sử dụng bộ nhớ. Tuổi không hoạt động được tính toán theo cấp số nhân giữa hai tham số để giảm thiểu công việc trong khi không chịu áp lực về bộ nhớ. 7200 (2 giờ)
mmd.zram.recompression.max_idle_seconds Số giây tối đa dùng để tính tuổi của trang không hoạt động một cách linh hoạt. 14400 (4 giờ)
mmd.zram.recompression.threshold_bytes Kích thước tối thiểu tính bằng byte của các trang ZRAM được xem xét để nén lại. 1024 (1 KiB)
mmd.zram.recompression.huge.enabled Chọn có bật tính năng nén lại trang HUGE hay không. true
mmd.zram.recompression.idle.enabled Chọn có bật tính năng nén lại trang IDLE hay không. true
mmd.zram.recompression.huge_idle.enabled Chọn có bật tính năng nén lại trang HUGE_IDLE hay không. true

Theo dõi trang không hoạt động của ZRAM

mmd Việc bảo trì ZRAM đánh dấu các trang ZRAM là không hoạt động dựa trên thời gian kể từ lần truy cập gần đây nhất. Tính năng này yêu cầu bạn bật các cấu hình hạt nhân CONFIG_ZRAM_TRACK_ENTRY_ACTIME hoặc CONFIG_ZRAM_MEMORY_TRACKING. CONFIG_ZRAM_TRACK_ENTRY_ACTIME được bật theo mặc định trên các nhân GKI 6.18 trở lên. Trên các nhân trước đó, tính năng này có mức sử dụng bộ nhớ cao và không được bật theo mặc định.

Nếu không bật cấu hình kernel, hoạt động bảo trì ZRAM mmd sẽ quay lại logic thay thế phần mềm để theo dõi các trang ZRAM không hoạt động:

  1. Đánh dấu tất cả các trang ZRAM là không hoạt động khi mmd bắt đầu.

  2. Bỏ qua các lần bảo trì ZRAM tiếp theo cho đến khi hết khoảng thời gian tạm ngưng bắt buộc.

  3. ZRAM ghi lại hoặc nén lại các trang không hoạt động. Nếu vẫn còn các trang không hoạt động do giới hạn ghi lại, mmd sẽ tiếp tục ghi lại các trang trong lần bảo trì tiếp theo mà không đánh dấu các trang mới là không hoạt động (bỏ qua bước 4).

  4. Nếu tất cả các trang không hoạt động đều được ghi lại, hãy đánh dấu tất cả các trang ZRAM là không hoạt động một lần nữa và chuyển về bước 2. Nếu tính năng ghi lại ZRAM bị tắt, mmd sẽ đánh dấu tất cả các trang ZRAM là không hoạt động khi quá trình nén lại ZRAM diễn ra sau khoảng thời gian không hoạt động nén lại.

Hướng dẫn khắc phục sự cố và xác thực

Hãy làm theo các bước xác thực và quy trình khắc phục sự cố sau đây để xác minh và chẩn đoán các hoạt động mmd và ZRAM.

Xác thực chế độ thiết lập ZRAM

Cách xác minh rằng mmd đã định cấu hình thành công ZRAM trong quá trình khởi động:

  1. Kiểm tra thuật toán nén đang hoạt động và kích thước ổ đĩa:

    cat /sys/block/zram0/comp_algorithm
    cat /sys/block/zram0/disksize
    
  2. Xác minh các thuộc tính hệ thống mmd và trạng thái dịch vụ đang chạy:

    getprop | grep mmd.zram
    dumpsys -l | grep mmd
    

Xác thực hoạt động bảo trì và ghi lại ZRAM

Xác minh rằng các tác vụ bảo trì ghi lại và nén lại ZRAM đang hoạt động:

  1. Kiểm tra trạng thái thiết bị khối hỗ trợ:

    cat /sys/block/zram0/bd_stat
    
  2. Kiểm tra hiệu quả nén lại bằng cách theo dõi /sys/block/zram0/mm_stat. Những thay đổi về kích thước dữ liệu nén sẽ xuất hiện sau các chu kỳ bảo trì.

Xác thực tính năng ghi lại theo quy trình

Bạn có thể sử dụng những thông tin sau để xác thực rằng tính năng ghi lại theo quy trình đang hoạt động:

  • Kiểm tra adb logcat -s mmd để biết nhật ký ghi lại thành công hoặc thông tin chẩn đoán lỗi.

Các vấn đề thường gặp và thông tin chẩn đoán

Sau đây là những tình huống lỗi thường gặp mà người dùng có thể gặp phải:

  • WritebackDailyLimitExceeded: Lỗi này cho biết bạn đã đạt đến hạn mức mmd.zram.writeback.max_bytes_per_day. Khi điều này xảy ra, mmd sẽ tạm dừng ghi lại dữ liệu khi không hoạt động cho đến khi cửa sổ luân phiên 24 giờ tiếp tục.
  • Process prefetch or writeback failed: Bạn có thể thấy lỗi này trong logcat khi một ioctl không thành công. Các nguyên nhân phổ biến bao gồm:
    • EBADF hoặc ESRCH: Quá trình đích đã kết thúc trước khi mmd có thể gửi pidfd đến nhân.
    • ENOSPC: Phân vùng bộ nhớ dự phòng đã đầy hoặc hàng đợi thiết bị vòng lặp đã hết.
  • ZRAM chưa được thiết lập: Nếu mmd không định cấu hình được ZRAM khi khởi động, thì có thể là do swapon_all cũ hoặc các tập lệnh khởi động của nhà cung cấp đã khoá /dev/block/zram0 trước khi mmd có thể thực thi.