Low memory killer daemon

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