Lmkd查杀功能的详细步骤
LMKD(Low Memory Killer Daemon)是 Android 系统中负责监控内存压力并在内存不足时终止进程以释放内存的关键守护进程。其查杀功能涉及内存压力监测、查杀条件判断和目标进程选择等步骤。下面这张图清晰地展示了 LMKD 的核心工作流程:
一.详细查杀步骤
1. 内存压力监控
LMKD 通过以下一种或多种机制来感知系统内存压力:
- PSI(Pressure Stall Information)监控(Android 10及以上推荐):LMKD 订阅内核的 PSI 事件,监控因内存不足导致的任务执行延迟。当部分停滞(如
ro.lmk.psi_partial_stall_ms
,默认70ms)或完全停滞(如ro.lmk.psi_complete_stall_ms
,默认700ms)的阈值被突破时,即判定为内存压力事件。 - Vmpressure 信号:监听内核生成的 vmpressure 事件,其包含低(low)、中(medium)、高(critical)等压力等级。LMKD 会根据这些等级初步判断压力程度。
- Zone Watermarks(内存区域水位线):通过解析
/proc/zoneinfo
和/proc/meminfo
,计算系统的内存水位线(WMARK_LOW, WMARK_MIN 等)。当可用内存低于特定水位时触发相应操作。
2. 判断查杀条件与确定 min_score_adj
当监测到内存压力事件后,LMKD 并非立即查杀,而是需要综合判断:
- 压力等级与阈值:系统将当前监测到的压力水平(如 PSI 指标、vmpressure 等级或 zone watermark 水平)与预设的阈值进行比较。例如,在 PSI 机制下,当
avg10
(10秒内的平均压力)超过psi_partial_stall_ms
设定的阈值时,会触发查杀。 - 其他因素:LMKD 还会考虑内存抖动(thrashing)程度、交换空间(swap)使用情况等因素,以防误杀或确保查杀有效性。
- 确定 min_score_adj:根据上述判断,LMKD 会确定一个本次查杀的最低
oom_score_adj
阈值(min_score_adj
)。只有oom_score_adj
值大于或等于此阈值的进程才可能被终止。通常,压力越大,min_score_adj
值设定得越小(即允许查杀更重要的进程)。例如,在vmpressure
机制中,ro.lmk.critical
属性可设置为 0,表示在关键压力下任何进程(包括前台应用)都可能被终止。
3. 选择并终止目标进程
LMKD 按照进程的 oom_score_adj
值(从高到低,即优先级从低到高)来筛选目标。
- 选择策略:
- 终止最重进程:若系统属性
ro.lmk.kill_heaviest_task
为true
,LMKD 会在符合条件的oom_score_j
等级中,选择内存占用(RSS)最大的进程终止。这有助于用最少的杀进程次数释放尽可能多的内存,常用于感知层级的进程(adj <= 200)。 - 终止链表末尾进程:若上述属性为
false
,则选择对应 adj 级别链表末尾的进程(通常是最近被移入该级别的进程)。
- 终止最重进程:若系统属性
- 遍历与终止:LMKD 从
oom_score_adj
最大值(1000,最低优先级)开始向下遍历,直至min_score_adj
。在遍历过程中,一旦在某个 adj 级别找到了目标进程,便会调用kill_one_process
函数向其发送SIGKILL
信号强制终止该进程。LMKD 会评估此次终止释放的内存是否缓解了内存压力。如果压力仍未解除,可能会启动新一轮的查杀流程,并可能调整min_score_adj
。
核心配置属性
LMKD 的行为可通过以下系统属性调节,这些属性通常由设备制造商在 build.prop
中配置
:
属性 | 作用 | 默认值示例 |
---|---|---|
ro.lmk.use_psi | 是否使用 PSI 监视器(否则使用 vmpressure) | true |
ro.lmk.psi_partial_stall_ms | 部分 PSI 失速阈值(毫秒) | 70 |
ro.lmk.psi_complete_stall_ms | 完全 PSI 失速阈值(毫秒) | 700 |
ro.lmk.low | 低压力级别对应的最小 oom_adj 分数 | 1001 (通常禁用) |
ro.lmk.medium | 中压力级别对应的最小 oom_adj 分数 | 800 (缓存或非核心服务) |
ro.lmk.critical | 关键压力级别对应的最小 oom_adj 分数 | 0 (任何进程) |
ro.lmk.kill_heaviest_task | 是否优先杀死最重任务 | true (最佳决策)或 false (快速决策) |
ro.lmk.thrashing_limit_pct | 内存抖动限制百分比 | - |
主要查杀模式
Android 系统中的 LMKD 主要存在两种实现模式:
- 用户空间 lmkd(主流):运行在用户空间,利用 PSI 或 vmpressure 进行更精细的内存压力判断,并执行进程终止。这是目前主流的方式。
- 内核空间 LMK(传统):通过写入
/sys/module/lowmemorykiller/parameters/minfree
和adj
来设置内存阈值与 adj 的对应关系。当内存低于阈值时,内核直接终止对应 adj 级别的进程。此方式较粗糙,已逐渐被用户空间 lmkd 取代。
二.如果lmkd查杀到adj 200 的可感知进程,是查杀的太激进了么?为什么一直会查杀的这么狠
当 LMKD 频繁查杀 adj 值为 200 的可感知进程时,这通常表明系统内存资源确实非常紧张,或者当前的查杀策略配置可能过于激进。下面我们来具体分析原因和应对方法。
⚙️ 查杀原因分析:为何会“手狠”
LMKD 决定是否查杀以及查杀哪个进程,主要基于一套阈值规则。如果它频繁对 adj 200 的进程“动手”,通常是以下一个或多个原因造成的:
内存压力巨大:这是最根本的原因。当系统可用内存持续低于为 adj 200 进程所设定的内存阈值时,LMKD 就会启动查杀。这就像一个水池的水位不断跌破更高的警戒线,说明缺水严重。可能的情况有:
- 设备物理内存较小,或同时运行了太多消耗内存的应用。
- 存在内存泄漏,导致可用内存快速减少。
查杀策略配置:LMKD 的行为可以通过系统属性进行配置。例如,
。如果这些阈值设置得过于激进(例如,让系统过早地进入“关键压力”状态),就可能导致优先级较高的进程被提前清理。ro.lmk.critical
属性定义了在内存关键压力级别下可被杀死的进程的最低 oom_adj 分数PSI 监控机制触发:在新版 Android 中,LMKD 使用 PSI(Pressure Stall Information)监控内存压力
。如果系统因内存不足导致任务执行出现延迟(即“停滞”),并且停滞时间超过了设定的阈值(如ro.lmk.psi_partial_stall_ms
默认的 70ms),LMKD 就会触发行动。这可能发生在实际可用内存绝对值还不太低,但内存子系统已非常繁忙的时刻。选择了“最重”的进程:LMKD 有一个配置项
。如果你的可感知进程(如后台音乐应用)恰好占用了较多内存,即使其 adj 值不是最低的,也可能被优先选中以快速释放大量内存。ro.lmk.kill_heaviest_task
。当此选项设置为true
时,LMKD 会在符合条件的进程中选择内存占用(RSS)最大的那个进行终止
🔧 避免查杀的核心策略
首先,我们可以从应用和系统两个层面主动采取措施,降低内存压力触发的概率。
🔍 深入监控内存水位与压力
要全面诊断问题,你需要监控以下几个关键指标,它们能帮你更清晰地看到内存使用的全貌。
1. 查看系统内存水位线
这是理解内核内存回收行为的直接窗口。你可以通过以下命令查看详细数据:
cat /proc/zoneinfo | grep -E "Node|min|low|high"
怎么看:关注 pages free
(剩余页数)与 min
、low
、high
这三个水位线的位置关系。如果 pages free
持续在 low
甚至 min
附近徘徊,就说明系统内存压力巨大,LMKD很可能即将行动。单位是内存页,通常一页为4KB。
2. 监控PSI指标
PSI提供了传统水位线之外更精细的压力视角。你可以查看以下文件来获取PSI数据:
cat /proc/pressure/memory
generic_x86_arm:/ # cat /proc/pressure/memory
some avg10=0.00 avg60=0.00 avg300=0.00 total=3856932
full avg10=0.00 avg60=0.00 avg300=0.00 total=1561696
怎么看:输出中的 avg10
表示过去10秒的平均压力百分比。如果这个值,尤其是 full
指标下的值,持续偏高(例如超过20%),说明有相当一部分任务因为等待内存而处于停滞状态,即使此时绝对剩余内存可能看起来还“够用”。这解释了为何有时LMKD会“提前”行动。
3. 综合评估可用内存
不要只看 free
内存,那会严重低估系统的真实容量。更准确的指标是 Available
内存(在 cat /proc/meminfo
中查看)。
为什么:Available
内存 ≈ Free
内存 + 可立即回收的缓存和缓冲区内存。这个值才真正代表系统在不引发严重卡顿的情况下,还能分配多少新内存。
📈 构建完整的监控流程
建议你将这些检查点整合成一个诊断流程:
- 常规监控:定期检查
/proc/meminfo
中的MemAvailable
,这是系统内存健康度的晴雨表。 - 压力分析:当
MemAvailable
开始显著下降时,去查看/proc/pressure/memory
的PSI数据,确认是否存在因内存不足导致的性能瓶颈。 - 根本原因调查:如果PSI压力也很高,再通过
/proc/zoneinfo
观察具体的水位线情况,并利用ps
或top
命令定位是哪些进程占用了大量内存。
首先,理解PSI阈值的作用
这两个参数是LMKD使用PSI(Pressure Stall Information)监控机制的核心:
ro.lmk.psi_partial_stall_ms
:指的是在1秒的时间窗口内,如果至少有一个任务在内存分配上被阻塞(stall)的时间超过这个毫秒值,就会触发中等(MEDIUM)级别的内存压力事件。默认值通常是70毫秒(高性能设备)或200毫秒(低内存设备)。ro.lmk.psi_complete_stall_ms
:指的是在1秒的时间窗口内,如果所有非空闲任务在内存分配上被阻塞的总时间超过这个毫秒值,就会触发关键(CRITICAL)级别的内存压力事件。默认值通常是700毫秒。
简单来说,降低这些阈值会使LMKD对内存压力更敏感,可能更早开始杀进程;提高这些阈值则会使LMKD更“容忍”内存压力,从而减少查杀。
基于你的目标是避免查杀过于激进,核心思路是适当提高这两个参数的数值。
确认当前值并提高阈值
- 首先,通过
getprop
命令查看这些属性的当前值,例如:
- 首先,通过
adb shell getprop ro.lmk.psi_partial_stall_ms
adb shell getprop ro.lmk.psi_complete_stall_ms
建议采用小步渐进的调整方式。例如,先将 ro.lmk.psi_partial_stall_ms
从70毫秒尝试提高到 90-120毫秒,将 ro.lmk.psi_complete_stall_ms
从700毫秒尝试提高到 900-1000毫秒。这可以让LMKD在内存压力持续更长时间后才采取行动。
修改属性值
- 你需要Root权限才能永久修改这些系统属性。临时修改可以使用
setprop
命令,例如:
adb shell su -c "setprop ro.lmk.psi_partial_stall_ms 100"
永久修改通常需要修改设备的 build.prop
文件或在 system.prop
文件中添加定义,然后重启设备。
其他相关参数协同调整
单一调整PSI阈值可能不够,可以考虑同步调整以下参数以形成组合策略:
调整参数后,必须密切观察系统行为,避免调整过度导致系统因内存不足(OOM)而崩溃。
- 启用LMKD调试日志:设置
ro.lmk.debug
属性为true
,然后使用adb logcat | grep -i lmkd
查看详细的杀进程日志。关注触发杀进程时的压力级别、被杀进程的adj值以及系统内存状况。 - 监控PSI指标:直接查看
/proc/pressure/memory
文件,观察some
和full
指标在avg10
(过去10秒平均值)上的变化。这能帮你直观看到调整后的压力水平。 - 监控系统整体内存状态:使用
cat /proc/meminfo
命令,重点关注MemAvailable
字段,它比MemFree
更能反映系统的真实可用内存容量。