内存压力与回收:从 lmkd 通知到 onTrimMemory
2026/8/9大约 4 分钟进程与内存管理Android 14内存压力onTrimMemory回收
内存压力与回收:从 lmkd 通知到 onTrimMemory
上一章看了进程内部 GC。这一章回答:系统内存紧张时,从内核压力信号到应用回调 onTrimMemory(),逐级回收是怎么组织的?
onTrimMemory() 是 Framework 向存活进程发出的缓存回收提示,lmkd 则根据实时压力独立 选择进程。工程上不能假设每次查杀前都存在一次可依赖、可及时完成的回调窗口。
回调回收与进程查杀不是一条同步链
| 常见误解 | 正确理解 |
|---|---|
| 内存紧张时系统直接杀进程 | 系统会先逐级通知应用回收(onTrimMemory),最后才杀 |
| onTrimMemory 只是给“缓存进程”的 | 运行中的进程也会收到低内存等级回调 |
| 应用收到回调可以忽略 | 不及时释放会加快被杀或拖垮系统 |
核心结论
- 压力感知链:内核压力信号 → Framework 评估 → 应用回调 → lmkd 兜底。
onTrimMemory()有多个等级:UI 隐藏、运行中低/中/高、后台与完全回收。- 回调运行在主线程,应做轻量释放(缓存、图片、对象池)。
- 系统会先通知后台进程清理,再按 adj 杀进程。
- 应用及时响应回调,可以降低被杀概率并改善系统流畅度。
压力与回收主链
逐步解释:
- 压力信号:内核上报内存紧张。
- 评估:Framework 判断压力等级与哪些进程需要通知。
- 回调:应用收到
onTrimMemory(),自行释放。 - 兜底:回收不充分时,lmkd 按优先级杀进程。
常用回调等级
| 等级 | 含义 | 建议动作 |
|---|---|---|
| TRIM_MEMORY_UI_HIDDEN | UI 已隐藏 | 释放 UI 相关大对象 |
| TRIM_MEMORY_RUNNING_MODERATE/LOW/CRITICAL | 运行中但系统紧张 | 释放缓存,越高级越积极 |
| TRIM_MEMORY_BACKGROUND/COMPLETE | 后台且压力大 | 释放全部可重建资源 |
等级不是“越靠后越严重”的简单排序,而是按进程状态分场景;实现时按“可重建程度” 从小到大释放,保证最常用的缓存最后清。
源码证据
阅读目标:确认回调分发入口与等级定义。
正文指针:ComponentCallbacks2.java 的等级常量;ActivityManagerService.java 中的 内存压力处理与 trimMemory 调用。
// ComponentCallbacks2.java(伪代码,行号以 r75 为准)
int TRIM_MEMORY_RUNNING_MODERATE = 5;
int TRIM_MEMORY_RUNNING_LOW = 10;
int TRIM_MEMORY_RUNNING_CRITICAL = 15;
void onTrimMemory(int level);这段代码证明: 等级是系统定义的协议;onTrimMemory() 是应用参与的回收入口。 系统先按等级回调,再决定是否杀进程。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell am send-trim-memory <包名> <level>
adb shell dumpsys meminfo
adb logcat -v threadtime | grep -E "TrimMemory|lmkd|am_kill"am send-trim-memory 可以手动模拟回调等级,验证应用释放逻辑;dumpsys meminfo 看 前后内存变化;logcat 看系统真实的分发与杀进程记录。
常见误区
- “系统直接杀进程,回调没用”:回调是协商机制,先于杀进程。
- “onTrimMemory 只给后台”:运行中进程也会收到。
- “回调里做重活”:回调在主线程,应轻量释放。
- “全部缓存都清掉最好”:按可重建成本分级清理更合理。
延伸问题
- 系统如何决定给哪些进程分发哪个等级?
onLowMemory()与onTrimMemory()的关系是什么?- 图片缓存(LruCache)如何在回调中安全清理?
- 如何用 Perfetto 观察内存压力与回收事件?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
ComponentCallbacks2.java | 等级常量 | 回调协议 |
ActivityManagerService.java | 内存压力处理 | 分发与决策 |
lmkd | 兜底回收 | 杀进程 |
am send-trim-memory | 命令行 | 手动验证 |
公共路径:frameworks/base/core/java/android/content/ 与 frameworks/base/services/core/java/com/android/server/am/。行号以 r75 检索为准。
需要区分泄漏、堆上限与系统压力时,见 内存问题排查。