Android 低内存 killer 守护程序 (lmkd
) 进程会监控正在运行的 Android 系统的内存状态,并通过终止最不重要的进程来应对高内存压力,以使系统保持在可接受的性能水平。
关于内存压力
并行运行多个进程的 Android 系统可能会遇到系统内存耗尽的情况,并且需要更多内存的进程会遇到明显的延迟。内存压力(系统内存不足的状态)要求 Android 通过节流或终止不重要的进程、请求进程释放非关键的缓存资源等方式来释放内存(以缓解压力)。
从历史上看,Android 使用内核低内存 killer (LMK) 驱动程序(一种依赖于硬编码值的刚性机制)来监控系统内存压力。从内核 4.12 开始,LMK 驱动程序已从上游内核中移除,用户空间 lmkd
执行内存监控和进程终止任务。
压力暂缓信息
Android 10 及更高版本支持一种新的 lmkd
模式,该模式使用内核压力暂缓信息 (PSI) 监控器来检测内存压力。上游内核中的 PSI 补丁程序集(反向移植到 4.9 和 4.14 内核)测量任务因内存短缺而延迟的时间量。由于这些延迟直接影响用户体验,因此它们是确定内存压力严重程度的便捷指标。上游内核还包含 PSI 监控器,这些监控器允许特权用户空间进程(例如 lmkd
)为这些延迟指定阈值,并在内核违反阈值时订阅来自内核的事件。
PSI 监控器与 vmpressure 信号
由于 vmpressure
信号(由内核生成以用于内存压力检测并由 lmkd
使用)通常包含大量误报,因此 lmkd
必须执行过滤以确定内存是否处于真正的压力之下。这会导致不必要的 lmkd
唤醒,并占用额外的计算资源。使用 PSI 监控器可以更准确地检测内存压力,并将过滤开销降至最低。
使用 PSI 监控器
要使用 PSI 监控器而不是 vmpressure
事件,请配置 ro.lmk.use_psi
属性。默认值为 true
,这使 PSI 监控器成为 lmkd
的默认内存压力检测机制。由于 PSI 监控器需要内核支持,因此内核必须包含 PSI 反向移植补丁程序,并且必须在启用 PSI 支持 (CONFIG_PSI=y
) 的情况下进行编译。
内核 LMK 驱动程序的缺点
Android 弃用 LMK 驱动程序的原因有很多问题,包括:
- 低 RAM 设备必须进行积极的调整,即使这样,在具有大型文件支持的活跃页面缓存的工作负载下,性能仍然很差。性能差会导致抖动,并且无法终止进程。
- LMK 内核驱动程序依赖于可用内存限制,没有基于内存压力进行扩展。
- 由于设计的僵化性,合作伙伴经常自定义驱动程序,以便使其在其设备上工作。
- LMK 驱动程序挂钩到 slab 收缩器 API,该 API 不是为搜索目标和终止目标等繁重操作而设计的,这会减慢
vmscan
进程的速度。
用户空间 lmkd
用户空间 lmkd
实现与内核驱动程序相同的功能,但使用现有的内核机制来检测和估计内存压力。此类机制包括使用内核生成的 vmpressure
事件或压力暂缓信息 (PSI) 监控器来获取有关内存压力级别的通知,以及使用内存 cgroup 功能来限制基于进程重要性分配给每个进程的内存资源。
在 Android 10 中使用用户空间 lmkd
在 Android 9 及更高版本中,如果未检测到内核 LMK 驱动程序,则用户空间 lmkd
会激活。由于用户空间 lmkd
需要内核支持内存 cgroup,因此内核必须使用以下配置设置进行编译:
CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
终止策略
Userspace lmkd
支持基于 vmpressure
事件或 PSI 监控器、它们的严重程度以及其他提示(如交换空间利用率)的终止策略。低内存设备和高性能设备之间的终止策略有所不同。
- 在低内存设备上,系统应容忍更高的内存压力,将其视为正常运行模式。
- 在高性能设备上,内存压力应被视为异常情况,并且应在影响整体性能之前进行修复。
您可以使用 ro.config.low_ram
属性配置终止策略。
Userspace lmkd
还支持一种旧版模式,在该模式下,它使用与内核内 LMK 驱动程序相同的策略(即,可用内存和文件缓存阈值)进行终止决策。要启用旧版模式,请将 ro.lmk.use_minfree_levels
属性设置为 true
。
配置 lmkd
使用以下属性为特定设备配置 lmkd
。
属性 | 用途 | 默认值 |
---|---|---|
ro.config.low_ram
|
指定设备是低 RAM 设备还是高性能设备。 | false
|
ro.lmk.use_psi |
使用 PSI 监控器(而不是 vmpressure 事件)。 |
true |
ro.lmk.use_minfree_levels
|
使用可用内存和文件缓存阈值来制定进程终止决策(即,匹配内核内 LMK 驱动程序的功能)。 | false
|
ro.lmk.low
|
在低 vmpressure 级别下有资格被终止的进程的最低 oom_adj 分数。 |
1001 (已停用) |
ro.lmk.medium
|
在中 vmpressure 级别下有资格被终止的进程的最低 oom_adj 分数。 |
800 (已缓存或非必要的服务) |
ro.lmk.critical
|
在严重 vmpressure 级别下有资格被终止的进程的最低 oom_adj 分数。 |
0 (任何进程) |
ro.lmk.critical_upgrade
|
启用升级到严重级别。 | false
|
ro.lmk.upgrade_pressure
|
由于系统交换空间使用过多而升级级别的最大 mem_pressure 。 |
100 (已停用) |
ro.lmk.downgrade_pressure
|
由于仍有足够的可用内存,因此忽略 vmpressure 事件的最小 mem_pressure 。 |
100 (已停用) |
ro.lmk.kill_heaviest_task
|
终止最重的合格任务(最佳决策)与任何合格任务(快速决策)。 | false
|
ro.lmk.kill_timeout_ms
|
在执行终止操作后,在多长时间(以毫秒为单位)内不再执行其他终止操作。 | 0 (已停用) |
ro.lmk.debug
|
启用 lmkd 调试日志。 |
false
|
设备配置示例
PRODUCT_PROPERTY_OVERRIDES += \
ro.lmk.low=1001 \
ro.lmk.medium=800 \
ro.lmk.critical=0 \
ro.lmk.critical_upgrade=false \
ro.lmk.upgrade_pressure=100 \
ro.lmk.downgrade_pressure=100 \
ro.lmk.kill_heaviest_task=true
Android 11 中的 Userspace lmkd
Android 11 通过引入新的终止策略改进了 lmkd
。此终止策略使用 Android 10 中引入的 PSI 机制进行内存压力检测。Android 11 中的 lmkd
考虑了内存资源使用级别和抖动,以防止内存不足和性能下降。此终止策略取代了以前的策略,可用于高性能设备和低 RAM (Android Go) 设备。
内核要求
对于 Android 11 设备,lmkd
需要以下内核功能
- 包括 PSI 补丁并启用 PSI(Android 通用内核 4.9、4.14 和 4.19 中提供了向后移植)。
- 包括 PIDFD 支持补丁(Android 通用内核 4.9、4.14 和 4.19 中提供了向后移植)。
- 对于低 RAM 设备,包括内存 cgroup。
内核必须使用以下配置设置进行编译
CONFIG_PSI=y
在 Android 11 中配置 lmkd
Android 11 中的内存终止策略支持以下列出的调整旋钮和默认值。这些功能适用于高性能设备和低 RAM 设备。
属性 | 用途 | 默认值 | |
---|---|---|---|
高性能 | 低 RAM | ||
ro.lmk.psi_partial_stall_ms |
部分 PSI 停顿阈值(以毫秒为单位),用于触发低内存通知。如果设备收到内存压力通知的时间太晚,请减小此值以更早地触发通知。如果内存压力通知触发不必要,请增大此值以降低设备对噪声的敏感度。 | 70 |
200 |
ro.lmk.psi_complete_stall_ms |
完整 PSI 停顿阈值(以毫秒为单位),用于触发严重内存通知。如果设备收到严重内存压力通知的时间太晚,请减小此值以更早地触发通知。如果严重内存压力通知触发不必要,请增大此值以降低设备对噪声的敏感度。 | 700 |
|
ro.lmk.thrashing_limit |
workingset 重新缺页错误的最大量,以占总文件支持的页缓存大小的百分比表示。高于此值的 workingset 重新缺页错误意味着系统被认为正在抖动其页缓存。如果在内存压力期间设备性能受到影响,请减小该值以限制抖动。如果设备的性能因抖动原因而不必要地被终止,请增大该值以允许更多抖动。 | 100 |
30 |
ro.lmk.thrashing_limit_decay |
抖动阈值衰减,以原始阈值的百分比表示,用于在系统即使在终止后也无法恢复时降低阈值。如果持续抖动产生不必要的终止,请减小该值。如果在终止后对持续抖动的响应太慢,请增大该值。 | 10 |
50 |
ro.lmk.swap_util_max |
交换内存的最大量,以占总可交换内存的百分比表示。当交换内存增长超过此限制时,意味着系统已交换了其大部分可交换内存,但仍处于压力之下。当不可交换的分配产生内存压力时,可能会发生这种情况,而这无法通过交换来缓解,因为大部分可交换内存已交换出去。默认值为 100,这实际上禁用了此检查。如果在内存压力期间设备性能受到影响,同时交换空间利用率很高,并且可用交换空间级别没有降至 ro.lmk.swap_free_low_percentage ,请减小该值以限制交换空间利用率。 |
100 |
100 |
以下旧的调整旋钮也适用于新的终止策略。
属性 | 用途 | 默认值 | |
---|---|---|---|
高性能 | 低 RAM | ||
ro.lmk.swap_free_low_percentage |
可用交换空间的级别,以占总交换空间大小的百分比表示。lmkd 使用此值作为阈值,以确定何时将系统视为交换空间不足。如果 lmkd 在交换空间中存在过多空间时执行终止操作,请减小该百分比。如果 lmkd 终止操作发生得太晚,导致发生 OOM 终止,请增大该百分比。 |
20 |
10 |
ro.lmk.debug |
这会启用 lmkd 调试日志。在调整时启用调试。 |
false |