1. 课程导入
在 Android 系统中,内存不是“越大越好”的静态资源,而是一条持续被分配、回收、压缩与淘汰的动态流水线。应用启动、页面切换、后台保活、相机预览、游戏渲染,每一个动作都会改变内存水位;而系统必须在有限物理内存下,同时保证前台流畅、后台可控、整机不卡死。LMKD(Low Memory Killer Daemon)正是这条流水线末端的“守门人”:它根据内存压力信号,决定在什么时机、杀掉哪些进程、释放多少内存。理解 LMKD,不能只背参数,而要把它放回 Android 内存管理的完整链路中。
1.1 核心概念:从物理内存到进程优先级
Android 内存管理建立在 Linux 虚拟内存之上,但增加了移动端特有的约束。物理内存被划分为页帧,内核通过页表把虚拟地址映射到物理页;当空闲页不足时,内核先回收缓存页(page cache),再考虑换出匿名页(zram 压缩或 swap)。如果回收仍跟不上分配速度,就会触发直接回收(direct reclaim),表现为卡顿、掉帧甚至 ANR。LMKD 的介入点,正是在“内核回收已经吃力,但还没到整机崩溃”之前,主动杀掉低优先级进程。
要理解 LMKD,先要理解 Android 的进程优先级体系。系统为每个进程维护一个 oom_score_adj(OOM 调整值),数值越低越“重要”,越不容易被杀。前台进程接近 0,可见进程约 100,服务进程约 200~500,缓存进程可达 900~1000。LMKD 并不直接看“进程名字”,而是看这些优先级、内存用量和系统压力等级,综合判断谁该被牺牲。
- MemTotal / MemFree / MemAvailable:整机内存总量、完全空闲内存、可回收估算内存,是判断水位的起点。
- Swap / Zram:压缩交换空间,能延缓杀进程,但压缩与解压会消耗 CPU。
- PSI(Pressure Stall Information):内存、CPU、IO 的阻塞压力指标,LMKD 现代版本依赖它判断“是否已经影响体验”。
- oom_score_adj:进程优先级权重,决定被杀顺序。
- minfree / watermark:内存水位阈值,决定何时开始回收、何时开始杀进程。
1.2 整体知识框架:四层视角
本课程把 Android 内存与 LMKD 调优拆成四层:硬件与内核层(物理内存、zram、页回收、PSI)、系统服务层(AMS、LMKD、vmpressure、cgroup)、应用行为层(进程生命周期、后台限制、内存泄漏、大图与大对象)、观测与调优层(dumpsys、procstats、meminfo、lmkd 日志、perfetto)。四层之间是因果链:应用行为制造压力,内核感知压力,LMKD 执行决策,观测工具验证结果。
1.3 方法流程:一条可复用的调优路径
面对“手机内存紧张、后台被杀、前台卡顿”这类问题,推荐按以下流程推进,而不是一上来就改 minfree。
- 建立基线:在典型场景(冷启动、多任务切换、相机、游戏)下采集 MemAvailable、PSI、LMKD 杀进程日志、procstats 后台内存。
- 定位压力源:区分是缓存页不足、匿名页过多、zram 压缩率低,还是某个应用异常占用。
- 判断 LMKD 行为:查看杀进程的 oom_score_adj 分布、触发时的 PSI 值、杀进程频率,判断是“杀得太早”还是“杀得太晚”。
- 调整策略:优化应用内存、调整 zram 大小与压缩算法、修正 oom_score_adj 分组、微调 LMKD 阈值与 PSI 门限。
- 回归验证:对比调优前后的前台掉帧率、后台存活率、整机可用内存、杀进程次数,确认没有引入新的副作用。
1.4 关键参数与观测入口
下面这张清单汇总了本课程会反复使用的观测入口与参数,建议先建立感性认识。
| 类别 | 入口 / 参数 | 作用 |
|---|---|---|
| 内存总览 | dumpsys meminfo |
查看各进程 PSS、缓存、内核内存占用 |
| 进程统计 | dumpsys procstats --hours 3 |
观察后台进程内存与存活时长 |
| LMKD 日志 | logcat -b events | grep lmkd |
查看杀进程原因、被杀进程 adj 与内存 |
| 压力信号 | /proc/pressure/memory |
读取 PSI some/full 值,判断内存阻塞程度 |
| 水位参数 | ro.lmk.*、minfree |
控制 LMKD 触发阈值与策略 |
| 压缩交换 | zram、swappiness |
影响匿名页换出与压缩效率 |
1.5 案例场景:一次典型的“后台被杀”复盘
某应用在后台播放音乐,用户切到相机后音乐被中断。初步排查发现:相机启动瞬间申请大量图形内存,MemAvailable 快速下降,PSI some 值升高,LMKD 在压力达到门限后杀掉了音乐进程。这里的问题不一定是 LMKD“太激进”,而可能是音乐进程的 oom_score_adj 分组不合理,或者相机内存峰值过高。调优方向包括:修正音乐进程的 adj 分组、优化相机预览 buffer 复用、适当提高 zram 容量以吸收峰值。这个案例说明,LMKD 调优必须结合具体场景,不能孤立看参数。
1.6 实战路线图
后续章节将沿着“概念 → 观测 → 分析 → 调参 → 验证”的路线展开:先讲清 Android 内存模型与 LMKD 工作原理,再进入 dumpsys、procstats、PSI、perfetto 等工具实操,随后分析典型内存问题(泄漏、抖动、峰值、后台膨胀),最后落地 LMKD 参数调优与整机内存策略设计。每一章都会给出可复现的命令、日志片段和判断标准,帮助你把知识转化为可执行的调优动作。
# 快速建立内存基线的三条命令
adb shell dumpsys meminfo | head -40
adb shell cat /proc/pressure/memory
adb logcat -b events -d | grep -i lmkd | tail -30
当你能够从一行 LMKD 日志还原出“谁在占内存、压力从哪来、为什么杀它、杀完是否缓解”,这门课程的核心目标就达到了。