Trình giới hạn bộ nhớ

Android 17 trở lên hỗ trợ Trình giới hạn bộ nhớ (Memory Limiter), một dịch vụ hệ thống giúp giám sát và giới hạn mức sử dụng bộ nhớ của các quy trình ứng dụng bằng Linux cgroup v2. Trình giới hạn bộ nhớ ngăn các ứng dụng riêng lẻ tiêu tốn quá nhiều bộ nhớ hệ thống, giúp giảm áp lực về bộ nhớ trên toàn hệ thống và ngăn chặn việc tắt các quy trình quan trọng một cách quyết liệt do hết bộ nhớ (OOM).

Cơ chế

Trình giới hạn bộ nhớ tích hợp với Dịch vụ trình quản lý hoạt động (AMS) để theo dõi các sự kiện trong vòng đời của quy trình và các thay đổi về trạng thái. Trình giới hạn bộ nhớ thực thi các giới hạn bộ nhớ bằng hệ thống tệp cgroup v2 của kernel Linux.

Để sử dụng Trình giới hạn bộ nhớ, kernel của thiết bị phải hỗ trợ cgroup v2 và bộ điều khiển memory. Dịch vụ này đặc biệt dựa vào các thuộc tính sau:

memory.high
Giới hạn linh hoạt. Khi vượt quá giới hạn này, quy trình sẽ bị điều tiết và kernel sẽ cố gắng thu hồi bộ nhớ từ quy trình đó.
memory.swap.max
Giới hạn dung lượng không gian trao đổi mà quy trình có thể sử dụng.

Tác động đến ứng dụng

Các ứng dụng không vượt quá giới hạn bộ nhớ sẽ không bị ảnh hưởng bởi Trình giới hạn bộ nhớ.

Khi một ứng dụng vượt quá giới hạn memory.high, kernel sẽ loại bỏ bộ nhớ được sao lưu bằng tệp của ứng dụng và trao đổi bộ nhớ ẩn danh của ứng dụng đó để giữ cho ứng dụng nằm trong giới hạn. Do việc loại bỏ và trao đổi, ứng dụng có thể chạy chậm hơn.

Trong trường hợp cực đoan, nếu ứng dụng tiếp tục phân bổ bộ nhớ ẩn danh và thiết bị hết không gian trao đổi, thì ứng dụng có thể không phân bổ được bộ nhớ và do đó có khả năng gặp sự cố.

Giám sát quy trình

Theo mặc định, Trình giới hạn bộ nhớ giám sát các quy trình ứng dụng (UID >= 10000). Các quy trình hệ thống thường được miễn trừ để giúp xác minh tính ổn định của hệ thống cốt lõi.

Trình giới hạn bộ nhớ chỉ định các giới hạn bộ nhớ dựa trên trạng thái của quy trình:

  • Các quy trình hiển thị là các quy trình mà người dùng có thể nhận thấy, chẳng hạn như hoạt động trên nền trước, dịch vụ trên nền trước hoặc các trạng thái khác mà người dùng có thể nhận thấy hiện tượng giật.

  • Các quy trình không hiển thị là các quy trình chạy trên nền sau mà người dùng không tương tác hoặc không nhìn thấy.

Bảng sau đây ánh xạ các trạng thái quy trình cụ thể với các giới hạn bộ nhớ:

Trạng thái quy trìnhGiới hạn bộ nhớ
PERSISTENTKhông hạn chế
PERSISTENT_UIKhông hạn chế
TOPĐã hiển thị
BOUND_TOPĐã hiển thị
FOREGROUND_SERVICEKhông hiển thị
BOUND_FOREGROUND_SERVICEKhông hiển thị
IMPORTANT_FOREGROUNDĐã hiển thị
IMPORTANT_BACKGROUNDKhông hiển thị
TRANSIENT_BACKGROUNDKhông hiển thị
BACKUPKhông hiển thị
SERVICEKhông hiển thị
RECEIVERKhông hiển thị
TOP_SLEEPINGĐã hiển thị
HEAVY_WEIGHTKhông hiển thị
HOMEKhông hiển thị
LAST_ACTIVITYKhông hiển thị
CACHED_ACTIVITYĐã lưu trong bộ nhớ đệm
CACHED_ACTIVITY_CLIENTĐã lưu trong bộ nhớ đệm
CACHED_RECENTĐã lưu trong bộ nhớ đệm
CACHED_EMPTYĐã lưu trong bộ nhớ đệm

Ở trạng thái đã lưu trong bộ nhớ đệm, các quy trình sẽ bị đóng băng rồi được thu hồi tối đa.

Khi một quy trình vượt quá giới hạn memory.high được chỉ định, Trình giới hạn bộ nhớ sẽ phát hiện sự kiện này và có thể kích hoạt các hành động gỡ lỗi, chẳng hạn như ghi lại hồ sơ bộ nhớ hoặc ghi lại một điểm bất thường vào statsd.

Cấu hình

Định cấu hình Trình giới hạn bộ nhớ bằng tệp XML nằm trên phân vùng vendor. Cấu hình cho phép bạn điều chỉnh các giới hạn bộ nhớ tuyệt đối dựa trên các ràng buộc bộ nhớ cụ thể của thiết bị.

  • Đường dẫn tệp: /vendor/etc/memory-limiter-config.xml

  • Cấu hình mặc định: Nếu không tìm thấy tệp cấu hình hoặc nếu tệp đó không đọc được hoặc không hợp lệ, thì Trình giới hạn bộ nhớ sẽ bị tắt.

Định dạng XML

Tệp cấu hình tuân theo giản đồ được xác định trong memory-limiter-config.xsd. Tệp này cho phép bạn xác định nhiều tập hợp giới hạn; dịch vụ sẽ chọn tập hợp phù hợp nhất dựa trên RAM có sẵn của thiết bị. Tất cả các giá trị bộ nhớ đều được xác định theo đơn vị mebibyte (MiB).

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <limitSet>
      <!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
Một số nguyên dương xác định phiên bản cấu hình. Giá trị này phải là 1.
minimumRequiredMemTotal
Bộ nhớ hệ thống tối thiểu cần thiết để tập hợp giới hạn này hợp lệ.
memVisible
Giới hạn bộ nhớ (memory.high) được phép cho các quy trình hiển thị.
memNotVisible
Giới hạn bộ nhớ (memory.high) được phép cho các quy trình không hiển thị.
swapVisible
Giới hạn trao đổi (memory.swap.max) được phép cho các quy trình hiển thị.
swapNotVisible
Giới hạn trao đổi (memory.swap.max) được phép cho các quy trình không hiển thị.

Nguyên tắc về giới hạn bộ nhớ thiết bị

Khi định cấu hình giới hạn bộ nhớ cho thiết bị, hãy cân nhắc các nguyên tắc sau:

  • Điều chỉnh giới hạn cho phù hợp với khả năng của phần cứng: Các OEM thiết bị có thể đặt các giới hạn phù hợp với khả năng của phần cứng thiết bị. Android đề xuất các phạm vi sau:

    • Các quy trình hiển thị: Ít nhất 1/2 và nhiều nhất 2/3 tổng RAM vật lý.
    • Các quy trình không hiển thị: 1/4 đến 1/3 tổng RAM vật lý. Các OEM có thể đưa ra các quyết định khác dựa trên khả năng và trường hợp sử dụng của thiết bị.
  • Không có API thời gian chạy cho ứng dụng: Kể từ Android 17 (SDK 37), các ứng dụng không có API để truy vấn các giới hạn bộ nhớ tại thời gian chạy. Các OEM nên cân nhắc điều này và tránh đặt giới hạn quá thấp, đảm bảo các ứng dụng không đạt đến giới hạn trong các trường hợp sử dụng hợp lý.

  • Cấu hình chung: Các giới hạn áp dụng cho tất cả các quy trình ứng dụng trên thiết bị, bao gồm cả các ứng dụng được cài đặt sẵn. Không có danh sách cho phép để miễn trừ một số ứng dụng khỏi các giới hạn này.

Sửa đổi cấu hình

Để thay đổi các giới hạn trên toàn hệ thống, hãy làm theo các bước sau:

  1. Sửa đổi /vendor/etc/memory-limiter-config.xml.
  2. Khởi động lại thiết bị hoặc khởi động lại system_server để các thay đổi có hiệu lực.

Lệnh shell

Lệnh am memory-limiter cho phép bạn và các nhà phát triển tương tác với dịch vụ tại thời gian chạy để phát triển và kiểm thử:

am memory-limiter <SUB-COMMAND>

trạng thái

Lệnh phụ status báo cáo trạng thái hoạt động của Trình giới hạn bộ nhớ:

adb shell am memory-limiter status

Kết quả điểm dữ liệu:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

Các trường chính trong kết quả bao gồm:

monitoring
Cho biết liệu trình giới hạn có đang chủ động theo dõi các quy trình hay không.
visibleMemnotVisibleMem
Cho biết các giới hạn bộ nhớ tuyệt đối được tính toán cho từng trạng thái.
events
Số lần một quy trình vượt quá giới hạn.
processes
Số quy trình được giám sát.

bỏ qua

Lệnh phụ ignore tạm thời loại trừ một UID hoặc tất cả các quy trình khỏi việc bị giới hạn. Hành động này hữu ích cho việc kiểm thử hiệu suất hoặc khi cho phép một ứng dụng cụ thể vượt quá giới hạn.

adb shell am memory-limiter ignore 10087  // Ignore a specific UID
adb shell am memory-limiter ignore all    // Ignore all processes (effectively disables limiting)
adb shell am memory-limiter ignore none   // Resume normal operation

thủ công

Lệnh phụ manual ghi đè các giới hạn được tính toán cho một quy trình cụ thể (theo mã quy trình hoặc PID) bằng một giá trị tuyệt đối tuỳ chỉnh tính bằng megabyte (MB):

adb shell am memory-limiter manual 1234 1024   // Set a 1024 MB limit for PID 1234
adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234

Các chế độ ghi đè thủ công chỉ áp dụng cho vòng đời của quy trình. Nếu quy trình khởi động lại, quy trình đó sẽ quay lại các giới hạn mặc định dựa trên trạng thái của quy trình.