Android 17 trở lên có Trình giới hạn bộ nhớ, 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 phiên bản 2. Trình giới hạn bộ nhớ ngăn chặn từng ứng dụng riêng lẻ tiêu thụ bộ nhớ hệ thống không cân xứng, giúp giảm áp lực bộ nhớ tổng thể và ngăn chặn việc tắt ứng dụng khi bộ nhớ thấp đối với các quy trình quan trọng ở nền trước và bộ nhớ đệm.
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 cách sử dụng hệ phân cấp cgroup v2 của nhân Linux.
Để hỗ trợ Trình giới hạn bộ nhớ, nhân thiết bị phải bật cgroup phiên bản 2 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, quy trình sẽ bị điều tiết và nhân hệ điều hành sẽ cố gắng chủ động thu hồi trang từ quy trình đó.
memory.swap.max- Giới hạn dung lượng tối đa của không gian hoán đổi (chẳng hạn như ZRAM) mà quy trình có thể sử dụng.
Tác động đến ứng dụng
Các ứng dụng hoạt động trong 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, nhân hệ điều hành sẽ loại bỏ bộ nhớ dựa trên tệp sạch của ứng dụng và hoán đổi bộ nhớ ẩn danh không hoạt động để giữ cho ứng dụng nằm trong giới hạn. Do hoạt động hoán đổi và loại bỏ trang này, ứng dụng có thể bị điều tiết thực thi tạm thời, nhưng vẫn tiếp tục chạy.
Trong những trường hợp nghiêm trọng (chẳng hạn như rò rỉ bộ nhớ không kiểm soát được, trong đó ứng dụng tiếp tục phân bổ bộ nhớ ẩn danh sau khi không gian hoán đổi đã hết), ứng dụng sẽ không phân bổ được bộ nhớ và bị chấm dứt.
Giám sát quy trình
Theo mặc định, Trình giới hạn bộ nhớ sẽ giám sát các quy trình của ứng dụng (UID >= 10000). Các quy trình cốt lõi của hệ thống được miễn trừ để duy trì độ ổn định cần thiết của hệ thống.
Trình giới hạn bộ nhớ chỉ định giới hạn bộ nhớ dựa trên trạng thái hiển thị của quy trình:
Quy trình hiển thị: Quy trình lưu trữ giao diện người dùng mà người dùng có thể nhìn thấy (chẳng hạn như hoạt động đang được chú ý hoặc hoạt động tương tác đang diễn ra). Vì việc hiển thị giao diện người dùng đòi hỏi một tập hợp hoạt động lớn hơn cho quy trình kết xuất và đồ hoạ, nên các quy trình hiển thị sẽ nhận được giới hạn bộ nhớ lớn hơn.
Quy trình không hiển thị: Quy trình thực hiện công việc ở chế độ nền mà không hiển thị giao diện người dùng (chẳng hạn như dịch vụ nền hoặc bộ nhận tín hiệu truyền tin). Vì không kết xuất các thành phần giao diện người dùng, nên các tiện ích này hoạt động theo một giới hạn nghiêm ngặt hơn.
Bảng sau đây liên kết các trạng thái quy trình cụ thể với các phân loại giới hạn bộ nhớ:
| Trạng thái quy trình | Giới hạn bộ nhớ |
|---|---|
PERSISTENT | Không hạn chế |
PERSISTENT_UI | Không hạn chế |
TOP | Đã hiển thị |
BOUND_TOP | Đã hiển thị |
FOREGROUND_SERVICE | Không hiển thị |
BOUND_FOREGROUND_SERVICE | Không hiển thị |
IMPORTANT_FOREGROUND | Đã hiển thị |
IMPORTANT_BACKGROUND | Không hiển thị |
TRANSIENT_BACKGROUND | Không hiển thị |
BACKUP | Không hiển thị |
SERVICE | Không hiển thị |
RECEIVER | Không hiển thị |
TOP_SLEEPING | Đã hiển thị |
HEAVY_WEIGHT | Không hiển thị |
HOME | Không hiển thị |
LAST_ACTIVITY | Khô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 vào bộ nhớ đệm, các quy trình sẽ bị đóng băng và sau đó đượ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 và có thể kích hoạt các hành động chẩn đoán, chẳng hạn như ghi lại hồ sơ bộ nhớ hoặc ghi lại điểm bất thường vào statsd.
Cấu hình
Trong Android 17 trở lên, Trình giới hạn bộ nhớ được định cấu hình bằng tệp cấu hình nền tảng tiêu chuẩn trên phân vùng hệ thống tại /system/etc/memory-limiter-config.xml.
Đị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 xác định nhiều nhóm giới hạn được sắp xếp theo bộ nhớ còn trống; dịch vụ sẽ chọn nhóm giới hạn phù hợp cao nhất dựa trên RAM còn trống của thiết bị. Tất cả giá trị bộ nhớ đều được chỉ định bằng mebibyte (MiB).
<MemoryLimiterConfig>
<version>1</version>
<configList>
<!-- RAM boundaries account for MemTotal excluding carve-outs. -->
<limitSet>
<!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
<memVisible>10240</memVisible>
<memNotVisible>5120</memNotVisible>
<swapVisible>5120</swapVisible>
<swapNotVisible>5120</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
<minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
<maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
<minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
<maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
<memVisible>5120</memVisible>
<memNotVisible>3072</memNotVisible>
<swapVisible>3072</swapVisible>
<swapNotVisible>3072</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
<minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
<maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
<memVisible>4096</memVisible>
<memNotVisible>2048</memNotVisible>
<swapVisible>2048</swapVisible>
<swapNotVisible>2048</swapNotVisible>
</limitSet>
<limitSet>
<!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
<minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
<maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
<memVisible>2048</memVisible>
<memNotVisible>1024</memNotVisible>
<swapVisible>1024</swapVisible>
<swapNotVisible>1024</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. minimumRequiredMemTotalMemTotalhệ thống tối thiểu (tính bằng MiB, bao gồm cả mức tối thiểu) cần thiết để áp dụng bộ giới hạn này. Dịch vụ này đánh giá mức sử dụng bộ nhớ so với tổng bộ nhớ hiện có mà nhân hệ điều hành báo cáo trong/proc/meminfo.Tìm hiểu về ranh giới và phần bộ nhớ được phân bổ: Giá trị hạt nhân
MemTotalphản ánh DRAM vật lý mà hệ điều hành có thể truy cập sau khi trừ đi phần bộ nhớ được phân bổ cho phần cứng và chương trình cơ sở. Phần dành riêng sẽ dự trữ RAM cho các thành phần phần cứng chuyên biệt như GPU, modem băng tần cơ sở, ISP của camera, môi trường thực thi bảo mật và trình ảo hoá, thường tiêu thụ từ 500 MiB đến hơn 2 GiB bộ nhớ vật lý.Vì
MemTotalthấp hơn DRAM vật lý được quảng cáo của thiết bị, nên ngưỡngminimumRequiredMemTotalbao gồm một biên độ cho các phần bị cắt giảm này. Ví dụ: một cấu hình nhắm đến thiết bị 16 GB sẽ chỉ định mức tối thiểu là14336(14 GiB) thay vì16384(16 GiB) và một cấp cho thiết bị 12 GB sẽ chỉ định mức tối thiểu là9216(9 GiB). Điều này đảm bảo rằng mỗi thiết bị đều khớp với cấp dự kiến, bất kể các biến thể phân chia ở cấp bo mạch.maximumAllowedMemTotalMemTotalhệ thống tối đa (tính bằng MiB, không bao gồm mức trần) để áp dụng giới hạn này. NếuMemTotallớn hơn hoặc bằng mức trần này, thì giới hạn đã đặt sẽ không áp dụng. Đối với các thiết bị có bộ nhớ từ 18.432 MiB trở lên hoặc các thiết bị có bộ nhớ dưới 3.200 MiB, Trình giới hạn bộ nhớ sẽ không áp dụng giới hạn, khiến các quy trình không bị ràng buộc.memVisibleGiới hạn bộ nhớ mềm (
memory.high) tính bằng MiB áp dụng cho các quy trình hiển thị.memNotVisibleGiới hạn bộ nhớ mềm (
memory.high) tính bằng MiB được áp dụng cho các quy trình không hiển thị.swapVisibleGiới hạn không gian hoán đổi (
memory.swap.max) tính bằng MiB áp dụng cho các quy trình hiển thị.swapNotVisibleGiới hạn không gian hoán đổi (
memory.swap.max) tính bằng MiB được áp dụng cho các quy trình không hiển thị.
Giới hạn tiêu chuẩn của nền tảng
Trong Android 17 trở lên, nền tảng này chỉ định giới hạn bộ nhớ và hoán đổi tiêu chuẩn trong /system/etc/memory-limiter-config.xml trên các cấp RAM vật lý phổ biến bằng cách sử dụng khoảng [floor, ceiling):
| RAM vật lý mục tiêu |
Phạm vi MemTotal [floor, ceiling) (minimumRequiredMemTotal, maximumAllowedMemTotal) |
Giới hạn bộ nhớ hiển thị (memVisible) |
Giới hạn bộ nhớ không hiển thị (memNotVisible) |
Giới hạn hoán đổi hiển thị (swapVisible) |
Giới hạn hoán đổi không hiển thị (swapNotVisible) |
|---|---|---|---|---|---|
| 16 GB | [14336, 18432) MiB |
10.240 MiB (10 GiB) | 5.120 MiB (5 GiB) | 5.120 MiB (5 GiB) | 5.120 MiB (5 GiB) |
| 12 GB | [9216, 14336) MiB |
8.192 MiB (8 GiB) | 4.096 MiB (4 GiB) | 4.096 MiB (4 GiB) | 4.096 MiB (4 GiB) |
| 8 GB | [6800, 9216) MiB |
5.120 MiB (5 GiB) | 3.072 MiB (3 GiB) | 3.072 MiB (3 GiB) | 3.072 MiB (3 GiB) |
| 6 GB | [4800, 6800) MiB |
4.096 MiB (4 GiB) | 2.048 MiB (2 GiB) | 2.048 MiB (2 GiB) | 2.048 MiB (2 GiB) |
| 4 GB | [3200, 4800) MiB |
2.048 MiB (2 GiB) | 1.024 MiB (1 GiB) | 1.024 MiB (1 GiB) | 1.024 MiB (1 GiB) |
Nguyên tắc về giới hạn bộ nhớ
Cấu hình của Trình giới hạn bộ nhớ được thiết kế dựa trên các nguyên tắc sau đây của nền tảng:
Tính nhất quán của hệ sinh thái và khả năng tương thích của ứng dụng: Giới hạn bộ nhớ nhất quán trên các thiết bị đảm bảo hiệu suất ứng dụng có thể dự đoán được trong toàn bộ hệ sinh thái Android. Ứng dụng được phát triển và thử nghiệm theo mức bộ nhớ chuẩn; việc duy trì các giới hạn đồng nhất của nền tảng giúp tránh tình trạng điều tiết ngoài dự kiến hoặc chấm dứt sớm.
Phân bổ tài nguyên theo tỷ lệ: Giới hạn của nền tảng được điều chỉnh theo dung lượng RAM vật lý:
- Quy trình hiển thị: Được phân bổ khoảng 1/2 đến 2/3 tổng RAM vật lý để hỗ trợ giao diện người dùng đang hoạt động, thành phần và khối lượng công việc kết xuất.
- Quy trình không hiển thị: Được phân bổ khoảng 1/4 đến 1/3 tổng dung lượng RAM thực tế cho các tác vụ trong nền.
Khả năng áp dụng chung: Các giới hạn được áp dụng đồng nhất cho tất cả quy trình của ứng dụng trên thiết bị (UID >= 10000), bao gồm cả ứng dụng hệ thống và ứng dụng OEM được cài đặt sẵn. Trình giới hạn bộ nhớ không hỗ trợ danh sách cho phép để miễn trừ các ứng dụng cụ thể, đảm bảo quản lý bộ nhớ công bằng trên tất cả các ứng dụng. Để định cấu hình mức bảo vệ tối thiểu
memory.mintự điều chỉnh trên các trình nền tương tác quan trọng và mức tối đamemory.highchặt chẽ hơn, được điều chỉnh theo khối lượng công việc trên từng ứng dụng và dịch vụ hệ thống, hãy xem phần Ngân sách bộ nhớ hệ thống.Không có API truy vấn thời gian chạy: Trên Android 17 trở lên, ứng dụng không thể truy vấn giới hạn bộ nhớ được chỉ định theo phương thức lập trình trong thời gian chạy. Giới hạn nền tảng tiêu chuẩn được xác định với biên độ rộng để các ứng dụng hoạt động tốt mà không bị ràng buộc trong quá trình sử dụng thông thường.
Động lực thu hồi và hoán đổi nhân hệ điều hành: Khi một quy trình ứng dụng đạt đến giới hạn
memory.high, nhân hệ điều hành Linux sẽ chỉ đạo việc thu hồi bộ nhớ cụ thể tại cgroup của quy trình đó. Điều này bao gồm việc loại bỏ các trang được hỗ trợ tệp không hoạt động và hoán đổi các trang ẩn danh không hoạt động sang ZRAM, duy trì tính linh hoạt của hệ thống mà không gây áp lực lên bộ nhớ chung.
Lệnh shell
Lệnh am memory-limiter cho phép nhà phát triển và nhà tích hợp hệ thống tương tác với dịch vụ trong thời gian chạy để phát triển, kiểm thử và gỡ lỗi:
am memory-limiter <SUB-COMMAND>trạng thái
Lệnh phụ status báo cáo trạng thái hoạt động và các chỉ số đang hoạt động của Bộ giới hạn bộ nhớ:
adb shell am memory-limiter statusSau đây là kết quả mẫ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 bộ nhớ có đang chủ động theo dõi các quy trình hay không.
visibleMemvànotVisibleMem- Giới hạn bộ nhớ tuyệt đối được tính toán (
memory.high) hiện được thực thi cho từng trạng thái hiển thị. visibleSwapvànotVisibleSwap- Giới hạn hoán đổi tuyệt đối được tính toán (
memory.swap.max) hiện được thực thi cho từng trạng thái hiển thị. events- Số lần một quy trình vượt quá giới hạn được chỉ định.
processes- Số lượng quy trình hiện đang được giám sát.
bỏ qua
Lệnh phụ ignore tạm thời loại trừ một UID cụ thể hoặc tất cả các quy trình khỏi giới hạn bộ nhớ. Điều này rất hữu ích cho việc đo điểm chuẩn hiệu suất, kiểm thử áp lực hoặc chẩn đoán hành vi của bộ nhớ:
# Ignore a specific UID adb shell am memory-limiter ignore 10087# Ignore all processes (temporarily disables limiting) adb shell am memory-limiter ignore all# Resume normal limiting operation adb shell am memory-limiter ignore none
thủ công
Lệnh phụ manual ghi đè giới hạn đã tính toán cho một tiến trình cụ thể theo mã định danh tiến trình (PID) bằng một giá trị tuyệt đối tuỳ chỉnh tính bằng byte. Giá trị phải là một số nguyên, nhưng có thể bao gồm hậu tố MB để biểu thị MiB hoặc hậu tố GB để biểu thị GiB:
# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1073741824# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1024MB# Set a 1GiB limit for PID 1234 adb shell am memory-limiter manual 1234 1GB# Remove the manual override for PID 1234 adb shell am memory-limiter manual 1234 none
Các chế độ ghi đè thủ công chỉ áp dụng cho thời gian hoạt động của phiên bản quy trình cụ thể đó. Nếu quy trình này khởi động lại, thì quy trình này sẽ trở về hạn mức tiêu chuẩn dựa trên trạng thái của quy trình.
Việc ghi đè thủ công không được vượt quá giới hạn của hệ thống vật lý.