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最高的进程 发送SIGKILL信号 释放内存,继续监控 继续监控,不做处理

从图中可以看出,LMK的工作流程其实很清晰:

  1. 系统持续监控可用内存
  2. 当内存低于某个阈值时,触发回收
  3. 从oom_adj最高的进程开始,逐个杀掉
  4. 释放内存后,继续监控

LMK的局限性

LMK虽然好用,但也不是万能的。我遇到过几个典型问题:

  • 误杀问题:有时候LMK会杀掉用户正在使用的应用。比如用户切到后台回了个微信,再切回来发现应用被杀了。这种情况在低内存手机上特别常见。
  • 杀不干净:有些应用被杀后会自动重启,导致LMK反复工作,反而增加了系统负担。
  • 阈值设置不合理:不同手机的内存大小不同,如果阈值设置得太高,会导致频繁杀进程;设置得太低,又会导致内存不足。

个人建议:如果你在开发应用,可以通过监听onTrimMemory()回调来主动释放资源。这样当LMK来临时,你的应用可能因为占用内存较少而「幸免于难」。我在项目中就经常用这个技巧,效果还不错。

总结

LMK是Android内存管理的最后一道防线。它通过oom_adj分数来区分进程的优先级,在内存不足时优先杀掉不重要的进程。虽然它有一些局限性,但整体上保证了系统的稳定运行。

理解LMK的原理,对我们做Android开发很有帮助。至少下次遇到应用被杀的问题,你知道该从哪里入手排查了。

公众号:蓝海资料掘金营,微信deep3321