1、内存管理概述:Android内存管理架构、内存阈值的作用、OOM Killer机制简介
各位同学好,我是老张。今天咱们开始聊Android内存管理。说实话,这个主题我讲了快十年,每次都有新感悟。你想想看,手机卡顿、应用被杀、系统重启——这些问题的根子,十有八九都出在内存管理上。
嗯,咱们先搭个框架。这一节我会把内存管理的整体架构、阈值的作用、还有那个让人又爱又恨的OOM Killer,一次性讲清楚。
1.1 Android内存管理架构
Android的内存管理,说白了就是一套「资源分配与回收」的机制。它不像Linux桌面系统那样,内存不够了就疯狂swap。移动设备没有那么大容量的交换空间,所以策略完全不同。
我习惯把Android内存管理分成三层来看:
- 内核层(Kernel):负责物理内存的分配与回收。Low Memory Killer(LMK)就住在这里。
- 系统服务层(System Server):AMS(ActivityManagerService)和WMS(WindowManagerService)在这里干活。它们决定「哪个进程该杀」。
- 应用框架层(Framework):提供ActivityManager、ProcessList等API给上层应用调用。
这三层的关系,我画个简图你感受一下:
应用层 (App)
↓ 调用
框架层 (AMS, ProcessList)
↓ 决策
系统服务层 (System Server)
↓ 执行
内核层 (LMK / OOM Killer)
↓ 回收
物理内存
我在项目中遇到过一个问题:某款手机在后台播放音乐时,突然被杀了。查了半天,发现是AMS在计算进程优先级时,把音乐进程的adj值算高了。这就是架构层之间配合出了问题。
1.2 内存阈值的作用
内存阈值,你可以理解为「水位线」。就像水库有警戒水位一样,Android系统也设了好几道线。
为什么要设阈值?直接原因就一个:防止系统彻底卡死。你想想看,如果内存被吃光了,连启动一个「杀进程」的线程都没空间了,那手机就真的死透了。
Android里常见的阈值有这些:
| 阈值名称 | 含义 | 典型值(4GB设备) |
|---|---|---|
| minfree | 各等级进程保留的最小空闲页数 | 12288, 15360, 18432, 21504 |
| adj | 进程优先级,值越大越容易被杀 | 0~1000 |
| cache_min | 缓存进程的最小数量 | 8~16 |
| extra_free_kbytes | 额外保留的可用内存 | 根据总内存动态计算 |
核心要点:阈值不是越高越好。设得太高,系统频繁杀进程,用户体验差;设得太低,内存耗尽才动手,系统容易卡死。这个平衡点,需要根据设备的内存大小、使用场景来调。
我记得有一次帮客户调优,他们的一款2GB内存的低端机,总是杀后台应用。我一看阈值配置,minfree设得跟4GB设备一样。这明显不合理。调低之后,后台留存率提升了30%。
1.3 OOM Killer机制简介
OOM Killer,全称Out-Of-Memory Killer。名字听着挺吓人,其实它就是个「最后的清道夫」。
它的工作逻辑很简单:当系统内存耗尽,无法再分配新内存时,OOM Killer会选择一个进程杀掉,释放内存。
但问题来了——杀谁?
OOM Killer不是随机选的。它有一套评分机制:
// 每个进程都有一个 oom_score_adj 值
// 值越大,越容易被杀
// 前台进程的 adj 值通常为 0
// 后台缓存进程的 adj 值可能高达 900~1000
// 内核计算 oom_score 的简化逻辑:
oom_score = 进程实际内存占用 + oom_score_adj 的加权值
说白了,就是「谁占内存多、谁优先级低,就杀谁」。
这里有个坑,我曾经踩过:某款手机在玩大型游戏时,突然黑屏重启。查log发现,游戏进程自己触发了OOM。为什么?因为游戏申请了一块超大纹理内存,系统来不及回收,直接触发了OOM Killer。而游戏进程的adj值虽然低,但它的内存占用太大了,评分一算,还是它自己中招。
避坑指南:OOM Killer不是bug,它是系统最后的保护机制。但如果你发现系统频繁触发OOM,那说明阈值配置或者内存泄漏有问题。不要试图禁用OOM Killer,那只会让系统死得更难看。
1.4 三者之间的关系
讲到这里,你可能有点晕:LMK、OOM Killer、阈值,它们到底怎么配合的?
我打个比方你就明白了:
- 内存阈值 = 水库的警戒水位线
- LMK(Low Memory Killer) = 日常巡逻的保安,水位超过警戒线就开始赶人(杀进程)
- OOM Killer = 最后的爆破队,大坝快垮了才出手
LMK是「预防性」的,它在内存还够用的时候就提前动手。OOM Killer是「补救性」的,它只在万不得已时才出手。
我个人习惯把LMK看作是第一道防线,OOM Killer是最后一道。调优的时候,优先优化LMK的阈值,让它在内存剩余15%~20%时就开始回收。这样OOM Killer基本不会触发。
小技巧:查看当前设备的LMK阈值,可以用 adb shell cat /sys/module/lowmemorykiller/parameters/minfree。如果看到四个数字,那就是四个等级对应的阈值。单位是「页」,1页=4KB。
好了,这一节的内容就到这里。内存管理架构是基础,阈值是调优的关键,OOM Killer是兜底机制。这三者搞明白了,后面讲具体配置策略时,你就能理解为什么这么设、不这么设会有什么后果。
下一节,咱们会深入分析LMK的源码实现,看看它到底是怎么「杀人」的。嗯,到时候我会带你们手撕一段内核代码。