1. 简介
LMKD,即Low memory killer daemon(低内存终止守护程序),该进程可监控Android系统中的内存状态,通过终止一些不必要的进程来解决内存压力大的问题,使系统以可接受的性能水平运行。
2. 内存压力(memory pressure)简介
在Android系统中,并行运行多个进程时,可能存在系统内存耗尽的情况,这时其它进程需要分配内存就会出现明显的延迟。内存压力(memory pressure),表示的时系统中内存不足的一种状态,需要Android释放系统中非关键缓存资源或者直接kill一些不必要的进程。
过去,Android使用内核中的LMK(low memory killer)驱动来监测内存压力,该驱动程序是一种依赖于hard-coded values的严格机制。
在kernel 4.12中,LMK 驱动程序已从上游内核中移除,改由用户空间 lmkd 来执行内存监控和进程终止任务。
3. 压力失速信息(Pressure stall information)
Android 10 及更高版本支持新的 lmkd 模式,它使用内核压力失速信息 (PSI,pressure stall information) 监视器来检测内存压力。上游内核中的 PSI 补丁程序集(已向后移植到 4.9 和 4.14 内核)可测量由于内存不足导致任务延迟的时间。由于这些延迟会直接影响用户体验,因此它们代表了确定内存压力严重性的便捷指标。上游内核还包括 PSI 监视器,这类监视器允许特权用户空间进程(例如 lmkd)指定这些延迟的阈值,并在突破阈值时从内核订阅events事件。
3.1 PSI monitors vs vmpressure signals
由于 vmpressure 信号(由内核生成,用于检测内存压力并由 lmkd 使用)通常包含大量误报,因此 lmkd 必须执行过滤以确定是否真的存在内存压力。这会导致不必要的 lmkd 唤醒并使用额外的计算资源。使用 PSI 监视器可以实现更精确的内存压力检测,并最大限度地减少过滤开销。
3.2 Using PSI monitors
如需使用 PSI 监视器(而不是 vmpressure 事件),请配置 ro.lmk.use_psi
属性。默认值为 true,这会以 PSI 监视器作为 lmkd 内存压力检测的默认机制。由于 PSI 监视器需要内核支持,因此内核必须包含 PSI 向后移植补丁程序,并在启用 PSI 支持 (CONFIG_PSI=y
) 的情况下进行编译。
4. 内核中LMK驱动的缺点
由于存在大量问题,Android 弃用了 LMK 驱动程序,问题包括:
- 对于低内存设备,必须主动进行调整,即便如此,在处理涉及支持大文件的活跃页面缓存的工作负载时,其性能也较差。性能不良会导致出现抖动,但不会终止。
- LMK 内核驱动程序依赖于可用内存限制,不会根据内存压力进行扩缩。
- 由于设计的严格性,合作伙伴通常会自定义该驱动程序,使其可以在自己的设备上使用。
- LMK 驱动程序已挂接到 Slab Shrinker API,该 API 并非为了执行繁重操作(例如搜索并终止目标)而设计,这类操作会导致 vmscan 进程变慢。
5. 用户空间中的lmkd
用户空间 lmkd 可实现与内核中的lmk驱动程序相同的功能,但它使用现有的内核机制检测和评估内存压力。这些机制包括使用内核生成的 vmpressure 事件或压力失速信息 (PSI) 监视器来获取关于内存压力水平的通知,以及使用内存 cgroup 功能限制根据进程的重要性分配给每个进程的内存资源。
5.1 在Android10的用户空间使用lmkd
在 Android 9 及更高版本中,用户空间 lmkd 会在未检测到内核中的 LMK 驱动程序时激活。由于用户空间 lmkd 要求内核支持内存 cgroup,因此必须使用以下配置设置编译内核:
CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
5.1.1 kill策略
用户空间 lmkd 支持基于以下各项的kill策略:
- vmpressure 事件
- PSI 监视器
根据它们的严重性以及其它一些提示,如swap 的利用率。
低内存设备(low-memory device)和高性能设备(high-performance device)的kill策略有所不同:
- 对于内存不足的设备,一般情况下,系统会选择承受较大的内存压力。
- 对于高性能设备,如果出现内存压力,则会视为异常情况,应及时修复,以免影响整体性能。
您可以使用 ro.config.low_ram
属性配置kill策略,为true时即为低内存设备。
用户空间 lmkd 还支持一种旧模式,在该模式下,它使用与内核中的 LMK 驱动程序相同的kill策略(即可用内存和文件缓存阈值(file cache thresholds))做出终止决策。要启用旧模式,请将 ro.lmk.use_minfree_levels
属性设置为 true。
5.1.2 配置 lmkd
使用以下属性为特定设备配置 lmkd。
属性 | 使用 | 默认 |
---|---|---|
ro.config.low_ram | 指定设备是低内存设备还是高性能设备。 | false |
ro.lmk.use_psi | 使用 PSI 监视器(而不是 vmpressure 事件)。 | true |
ro.lmk.use_minfree_levels | 使用可用内存和文件缓存阈值来做出进程终止决策(即与内核中的 LMK 驱动程序的功能一致)。 | false |
ro.lmk.low | 在低 vmpressure 水平下可被终止的进程的最低 oom_adj 得分。 | 1001(disabled) |
ro.lmk.medium | 在中等 vmpressure 水平下可被终止的进程的最低 oom_adj 得分。 | 800(cached or nonessential services) |
ro.lmk.critical | 在临界 vmpressure 水平下可被终止的进程的最低 oom_adj 得分。 | 0(any process) |
ro.lmk.critical_upgrade | 支持升级到critical level。 | false |
ro.lmk.upgrade_pressure | The maximum mem_pressure at which the level is upgraded because the system is swapping too much. | 100(disabled) |
ro.lmk.downgrade_pressure | The minimum mem_pressure at which a vmpressure event is ignored because enough free memory is still available. | 100(disabled) |
ro.lmk.kill_heaviest_task | 终止符合条件的最繁重任务(最佳决策)与终止符合条件的任何任务(快速决策)。 | true |
ro.lmk.kill_timeout_ms | 从某次终止后到其他终止完成之前的持续时间(以毫秒为单位)。 | 0(disabled) |
ro.lmk.debug | 启用 lmkd 调试日志。 | false |
注意:mem_pressure
= RAM usage
/RAM_and_swap usage
(以百分比的形式表示)。
设备配置示例:
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
5.2 在Android11使用lmkd
Android 11 通过引入新的kill策略(PSI)改进了 lmkd。该kill策略使用 PSI 机制来执行 Android 10 中引入的内存压力检测。Android 11 中的 lmkd 会根据内存资源使用情况和抖动来防止出现内存不足和性能下降。这一终止策略取代了以前的策略,可同时用于高性能设备和低内存 (Android Go) 设备。
5.2.1 内核要求
对于 Android 11 设备,lmkd 需要以下内核功能:
- 添加 PSI 补丁程序并启用 PSI(Android 通用内核 4.9、4.14 和 4.19 中提供向后移植)。
- 添加 PIDFD 支持补丁程序(Android 通用内核 4.9、4.14 和 4.19 中提供向后移植)。
- 对于低内存设备,添加内存 cgroup。
必须使用以下配置设置编译内核:
CONFIG_PSI=y
在 Android 11 中配置 lmkd
Android 11 中的内存kill策略支持下面列出的调节旋钮和默认值。这些功能在高性能设备和低内存设备上都可使用。
属性 | 使用 | 默认(High performance) | 默认(low ram) |
---|---|---|---|
ro.lmk.psi_partial_stall_ms | 部分 PSI 失速阈值(以毫秒为单位),用于触发内存不足通知。如果设备收到内存压力通知的时间太晚,可以降低此值以在较早的时间触发通知。如果在不必要的情况下触发了内存压力通知,请提高此值以降低设备对noise的敏感度。 | 70 | 200 |
ro.lmk.psi_complete_stall_ms | 完全 PSI 失速阈值(以毫秒为单位),用于触发critical内存通知。如果设备收到关键内存压力通知的时间太晚,可以降低该值以在较早的时间触发通知。如果在不必要的情况下触发了关键内存压力通知,可以提高该值以降低设备对noise的敏感度。 | 700 | 700 |
ro.lmk.thrashing_limit | 工作集 refault 数量的上限,以占具有文件支持的页面缓存总大小的百分比表示。如果工作集 refault 的数量超过该值,则视为系统对其页面缓存造成抖动。如果设备性能在内存压力期间受到影响,请降低该值以限制抖动。如果因抖动原因而导致设备性能不必要地降低,请提高该值以允许更多抖动。 | 100 | 30 |
ro.lmk.thrashing_limit_decay | 抖动阈值衰减,以占在系统无法恢复时(甚至是终止后)用于降低阈值的原始阈值的百分比表示。如果持续抖动导致不必要的终止,请降低该值。如果终止后对持续抖动的响应速度过慢,请提高该值。 | 10 | 50 |
ro.lmk.swap_util_max | 最大交换内存量,以占可交换内存总量的百分比表示。如果交换的内存量超过此上限,则表示系统在交换了其大部分可交换内存后仍然存在压力。 当内存压力是由不可交换内存的分配导致时,就可能会发生这种情况,原因在于大部分可交换内存已经交换,所以无法通过交换来缓解这一压力。默认值为 100,这实际上会停用此检查。如果设备的性能在交换利用率较高且可用交换水平未降至ro.lmk.swap_free_low_percentage 的内存压力期间受到影响,请降低该值以限制交换利用率。 | 100 | 100 |
以下旧的调节旋钮也可用于新的终止策略。
属性 | 使用 | 默认(High performance) | 默认(low ram) |
---|---|---|---|
ro.lmk.swap_free_low_percentage | 可用交换水平,以占总交换空间的百分比表示。“lmkd”使用该值作为阈值来判断何时将系统视为交换空间不足。如果“lmkd”因交换空间过多而终止,请降低该百分比。如果“lmkd”终止得太晚,从而导致 OOM 终止,请提高该百分比。 | 20 | 10 |
ro.lmk.debug | 这会启用“lmkd”调试日志。在调节时启用调试。 | false | false |
评论