4. LMKD核心概念
在Android内存管理体系中,LMKD(Low Memory Killer Daemon)是运行在用户空间的一个常驻守护进程,负责在系统内存紧张时决定“杀谁、何时杀、杀多少”。它并不是一个简单的替代品,而是Android从“内核被动回收”走向“用户空间主动决策”的关键组件。理解LMKD的定位、演进历史、与内核LowMemoryKiller(LMK)的本质区别,以及它的用户空间决策机制,是后续进行LMKD调优的前提。
一、LMKD的定位:用户空间的“内存压力仲裁者”
LMKD位于Android框架层与Linux内核之间,扮演内存压力仲裁者的角色。它通过内核提供的/proc/pressure/memory(PSI,Pressure Stall Information)或传统的vmpressure事件感知内存压力,再结合进程的oom_score_adj(OOM调整值)和进程状态,选择最合适的进程终止,以释放内存并维持系统流畅。
它的核心职责可以概括为三点:
- 感知压力:监听内核上报的内存压力事件,判断当前是轻度、中度还是重度紧张。
- 选择目标:根据进程的优先级、前台/后台状态、占用内存大小,计算“性价比”最高的终止对象。
- 执行终止:向目标进程发送
SIGKILL,并记录日志供调试与统计。
二、历史演进:从内核LMK到用户空间LMKD
Android早期版本(Android 1.5至6.x)依赖内核中的LowMemoryKiller驱动。该驱动以内核模块形式存在,通过扫描进程的oom_score_adj和内存阈值,在内存低于预设水位时直接杀进程。它的优点是响应快、无需用户空间参与;缺点是策略僵化、阈值固定、无法感知前台体验,且与内核OOM Killer存在职责重叠。
从Android 7.0(Nougat)开始,Google逐步将杀进程逻辑迁移到用户空间,引入LMKD。Android 9(Pie)之后,LMKD成为默认且唯一的低内存杀进程机制,内核LMK被彻底移除。Android 10及以后,LMKD进一步引入PSI(Pressure Stall Information)作为主要压力信号,使决策更精细、更贴近真实用户体验。
| 对比维度 | 内核LowMemoryKiller(LMK) | 用户空间LMKD |
|---|---|---|
| 运行位置 | Linux内核空间 | Android用户空间 |
| 压力信号 | 空闲内存水位(free memory) | PSI / vmpressure / 内存水位 |
| 策略灵活性 | 低,阈值固定在内核配置 | 高,可通过属性、配置动态调整 |
| 与框架协同 | 弱,无法感知Activity状态 | 强,结合oom_score_adj与进程状态 |
| 可观测性 | 内核日志,调试困难 | logcat、dumpsys、统计信息丰富 |
| Android版本 | Android 6及以前 | Android 7引入,Android 9后默认 |
三、与内核LowMemoryKiller的本质区别
两者最根本的区别在于决策依据与决策位置。内核LMK只看“还剩多少空闲内存”,当空闲内存低于某个阈值时,按oom_score_adj从大到小杀进程。这种机制的问题在于:空闲内存低并不一定代表用户正在经历卡顿,可能只是缓存占用多;而空闲内存高也不一定代表体验流畅,可能后台进程正在疯狂抢占CPU。
LMKD则引入了“压力”概念。PSI能够量化“因内存不足导致任务停顿的时间比例”,例如some avg10=0.50表示过去10秒内有0.5%的时间至少有一个任务因内存而停顿。LMKD根据压力等级(如low、medium、high、critical)采取不同策略:轻度压力时优先杀缓存进程,重度压力时才杀前台相关进程。这种“按压力分级、按优先级选择”的机制,比内核LMK的“一刀切”更符合Android多任务体验需求。
四、用户空间决策机制:LMKD如何选择目标
LMKD的决策流程可以概括为“感知—分级—选择—执行”四个步骤。下图展示了其核心决策链路与关键输入输出:
具体来说,LMKD在用户空间的决策机制包含以下关键点:
- 压力信号采集:优先使用PSI。LMKD读取
/proc/pressure/memory,获取some和full两种停顿指标。当some avg10超过psi_partial_stall_ms对应阈值时,进入相应压力等级。 - 压力等级映射:LMKD将压力分为
low、medium、high、critical四级。等级越高,允许终止的进程oom_score_adj范围越宽,甚至包括前台进程。 - 目标选择算法:在候选进程中,LMKD综合计算“释放内存收益”与“用户体验损失”。通常优先选择
oom_score_adj较大(优先级低)、内存占用较大、且最近未被使用的进程。 - 终止与反馈:发送
SIGKILL后,LMKD记录被杀进程的pid、oom_score_adj、释放内存量及当时压力等级,写入logcat和统计节点,供后续调优分析。
五、常见误区与复盘
复盘一个典型场景:某应用在后台被频繁杀死,日志显示lmkd: Kill 'com.example.app' (pid 12345), oom_score_adj=900, reason=low memory。这说明该进程的oom_score_adj较高(后台缓存进程),且系统处于内存压力状态。若希望它存活更久,应通过ActivityManager提升其优先级,或减少其内存占用,而不是直接修改LMKD的杀进程阈值。
# 查看LMKD相关属性
adb shell getprop | grep lmk
# 查看内存压力
adb shell cat /proc/pressure/memory
# 查看LMKD日志
adb logcat -s lmkd
# 查看进程oom_score_adj
adb shell cat /proc/<pid>/oom_score_adj
总结来说,LMKD是Android内存管理从内核态走向用户态、从“数量驱动”走向“压力驱动”的产物。它通过PSI感知真实卡顿压力,结合进程优先级进行分级决策,在系统内存紧张时以最小体验代价释放内存。理解其定位、演进、与内核LMK的区别以及用户空间决策机制,是后续进行LMKD参数调优和内存问题排查的基础。