Low Memory Killer:LMK原理,oom_adj分数,进程优先级与回收策略
大家好,今天我们来聊聊Android内存管理中一个非常核心的机制——Low Memory Killer(简称LMK)。
说实话,我刚开始接触Android系统时,对LMK的理解很浅。觉得不就是内存不够了杀进程嘛,有什么好研究的?直到有一次我在项目中遇到一个诡异的问题:手机在运行某个大型游戏时,突然黑屏重启了。查了半天,发现是LMK把系统服务给杀了,导致系统崩溃。嗯,从那以后,我再也不敢小看这个机制了。
LMK是什么?
LMK,全称Low Memory Killer,是Android内核层的一个内存回收机制。它的工作很简单:当系统内存不足时,根据进程的优先级,选择性地杀掉一些进程来释放内存。
你可能会问:为什么不用Linux标准的OOM Killer?
Linux的OOM Killer是在内存彻底耗尽时才触发,而且它的选择策略比较粗糙。Android作为移动操作系统,对用户体验要求更高。你想想看,如果用户正在刷抖音,突然因为内存不足导致抖音被杀了,那体验多糟糕?
所以Android搞了一套自己的机制——LMK。它会在内存还够用的时候,提前杀掉那些不那么重要的进程。说白了,就是「牺牲小我,保全大我」。
oom_adj分数:进程的「生死簿」
LMK怎么判断哪个进程该杀?靠的就是oom_adj分数。
每个进程都有一个oom_adj值,范围从-17到15。数值越小,优先级越高,越不容易被杀。数值越大,优先级越低,越容易被杀。
我习惯把这个值理解为进程的「生死簿」分数。分数高的,就是「炮灰」;分数低的,就是「核心骨干」。
| oom_adj值 | 进程类型 | 说明 |
|---|---|---|
| -17 | 系统核心进程 | 永远不被杀,比如init、zygote |
| 0 | 前台进程 | 用户正在交互的进程 |
| 1 | 可见进程 | 用户可见但不交互,比如悬浮窗 |
| 2 | 服务进程 | 正在运行服务的进程 |
| 3-5 | 后台进程 | 用户已切走的进程 |
| 6-15 | 空进程/缓存进程 | 没有任何活跃组件的进程 |
核心要点:oom_adj值越低,进程越安全。系统核心进程的oom_adj是-17,意味着它们永远不会被LMK杀掉。
进程优先级与回收策略
LMK的回收策略其实很简单:当可用内存低于某个阈值时,从oom_adj最高的进程开始杀,直到内存恢复到安全水平。
Android系统定义了多个内存阈值,每个阈值对应一个oom_adj值。举个例子:
- 当可用内存低于100MB时,杀掉oom_adj >= 15的进程(空进程)
- 当可用内存低于80MB时,杀掉oom_adj >= 9的进程(后台进程)
- 当可用内存低于60MB时,杀掉oom_adj >= 6的进程(可见进程)
- 当可用内存低于40MB时,杀掉oom_adj >= 1的进程(服务进程)
- 当可用内存低于20MB时,杀掉oom_adj >= 0的进程(前台进程)
这些阈值在不同手机上可能不一样。我记得在某个项目中,客户反馈手机经常卡顿,我查了一下发现是LMK阈值设置得太保守了,导致内存还没怎么用就开始杀进程。后来调整了阈值,问题就解决了。
避坑指南:我曾经遇到过一个问题:某个第三方应用在后台频繁拉起服务,导致oom_adj值不断变化。LMK每次杀完它,它又马上重启,形成了「杀-重启-再杀」的死循环。这种情况非常耗电,而且影响用户体验。解决方案是限制后台启动,或者将这类应用加入系统的「待机优化」列表。
LMK的工作流程
为了让大家更直观地理解LMK的工作流程,我画了一张图:
从图中可以看出,LMK的工作流程其实很清晰:
- 系统持续监控可用内存
- 当内存低于某个阈值时,触发回收
- 从oom_adj最高的进程开始,逐个杀掉
- 释放内存后,继续监控
LMK的局限性
LMK虽然好用,但也不是万能的。我遇到过几个典型问题:
- 误杀问题:有时候LMK会杀掉用户正在使用的应用。比如用户切到后台回了个微信,再切回来发现应用被杀了。这种情况在低内存手机上特别常见。
- 杀不干净:有些应用被杀后会自动重启,导致LMK反复工作,反而增加了系统负担。
- 阈值设置不合理:不同手机的内存大小不同,如果阈值设置得太高,会导致频繁杀进程;设置得太低,又会导致内存不足。
个人建议:如果你在开发应用,可以通过监听onTrimMemory()回调来主动释放资源。这样当LMK来临时,你的应用可能因为占用内存较少而「幸免于难」。我在项目中就经常用这个技巧,效果还不错。
总结
LMK是Android内存管理的最后一道防线。它通过oom_adj分数来区分进程的优先级,在内存不足时优先杀掉不重要的进程。虽然它有一些局限性,但整体上保证了系统的稳定运行。
理解LMK的原理,对我们做Android开发很有帮助。至少下次遇到应用被杀的问题,你知道该从哪里入手排查了。