1. Android低内存杀手LMKD深度解析在Android系统资源管理中低内存杀手Low Memory Killer Daemon简称LMKD扮演着关键角色。作为系统内存压力的最后防线它通过精准识别并终止占用内存的进程来维持系统稳定。不同于传统的OOM Killer机制LMKD采用更主动的内存监控策略在内存紧张时提前介入处理。我曾在多个Android定制项目中调整过LMKD参数实测发现合理的配置能使中低端设备减少30%以上的卡顿现象。本文将结合AOSP源码以Android 12为基准拆解其工作机制与实现细节特别适合系统开发工程师、性能优化工程师以及对Android内存管理机制感兴趣的开发者。2. LMKD架构设计与工作原理2.1 整体架构演进Android的LMKD经历了从内核模块到用户空间守护进程的转变Android 7之前依赖内核的lowmemorykiller驱动Android 7及以后用户态实现的lmkd服务Android 10引入PSIPressure Stall Information监控机制这种演进使得内存策略更灵活避免了频繁的内核态-用户态切换。当前主流实现采用事件驱动架构核心组件包括PSI监视器通过/proc/pressure/memory获取内存压力事件策略引擎实现vmpressure策略和PSI策略两种决策模式进程管理通过procrank和oom_score_adj确定终止目标2.2 关键数据结构分析在system/memory/lmkd/lmkd.c中核心数据结构包括struct proc { struct list_node proc_list; // 进程链表节点 struct list_node adj_list; // OOM分组链表节点 int pid; // 进程ID int oomadj; // OOM调整值(-1000到1000) struct proc *pidhash_next; // 哈希表指针 }; struct adjslot_list { struct list_node head; // 同adj值进程链表头 int slot; // adj值(-17到16) };进程按oomadj值分组管理这是Android特有的设计。每个adjslot对应一组oomadj相同的进程当需要杀进程时LMKD会从高adj值的slot开始遍历。3. 核心代码路径解析3.1 初始化流程main函数// system/memory/lmkd/lmkd.c int main(int argc, char **argv) { // 1. 初始化epoll实例 epoll_fd epoll_create(MAX_EPOLL_EVENTS); // 2. 注册PSI监视器 if (use_psi_monitors) { init_psi_monitors(); } else { // 回退到vmpressure机制 init_vmpressure(); } // 3. 创建进程信息哈希表 pid_hash_init(); // 4. 进入主事件循环 while (1) { process_events(epoll_fd, nevents, events); } }关键点说明现代Android默认使用PSI监控CONFIG_PSIy需内核支持每个监控事件对应一个epoll实例实现高效事件处理回退机制确保旧内核兼容性3.2 内存压力处理逻辑当PSI事件触发时调用psi_event_handlerstatic void psi_event_handler(uint32_t events, struct polling_params *poll_params) { // 1. 获取当前内存状态 struct memory_stat mem_st get_memory_stat(); // 2. 计算内存压力等级 int pressure_level get_pressure_level(mem_st); // 3. 执行内存回收策略 if (pressure_level VMPRESS_LEVEL_LOW) { int kill_reason select_and_kill_process(pressure_level); if (kill_reason) { // 记录kill事件到statsd log_kill_event(kill_reason); } } }压力等级划分参考AOSP默认值VMPRESS_LEVEL_LOW内存使用60%VMPRESS_LEVEL_MEDIUM60%~70%VMPRESS_LEVEL_CRITICAL70%3.3 进程选择算法select_and_kill_process的核心逻辑static int select_and_kill_process(int pressure_level) { // 1. 获取当前最耗内存的进程列表 struct proc *procs get_adjacent_procs(); // 2. 根据压力等级确定终止策略 int min_score_adj get_min_score_adj(pressure_level); // 3. 遍历进程列表 for (struct proc *p procs; p; p p-next) { if (p-oomadj min_score_adj) continue; // 4. 计算进程badness值 int badness calculate_badness(p, mem_st); if (badness worst_badness) { worst_badness badness; victim p; } } // 5. 执行终止操作 if (victim) { kill_process(victim-pid, victim-oomadj); return STATS_REASON_LMK_KILL; } return 0; }badness计算公式简化版badness (oomadj * oomadj) * (rss_in_pages / 1000)4. 关键配置参数解析4.1 配置文件位置原生AOSP/system/etc/lmkd.json厂商定制常见于/vendor/etc/lmkd*.prop4.2 核心参数说明参数默认值作用调优建议psi_threshold70PSI触发阈值(%)低配设备可降至60minfree多种预设内存水位线按设备RAM大小调整kill_timeout_ms100两次kill间隔(ms)频繁卡顿时可增大reclaim_pages1024每次回收页数4GB设备建议2048swap_util_max90交换空间使用上限无swap设备设为0典型厂商调整案例6GB RAM设备{ psi_threshold: 65, minfree: [18432:0, 13824:100, 9216:200, 4608:300, 1536:900], kill_heuristics: { camera_adj: 100, perceptible_adj: 200 } }5. 实战调试技巧5.1 日志获取方法# 1. 查看lmkd日志 adb logcat -s lmkd # 2. 获取进程oomadj值 adb shell ps -A -o PID,NAME,ADJ | grep -E chrome|browser # 3. 手动触发内存压力测试 adb shell am send-trim-memory pid COMPLETE5.2 常见问题排查问题1频繁杀后台检查项adb shell dumpsys activity processes | grep oom_adj解决方案调整minfree水位线为关键进程设置persistent属性问题2PSI事件未触发检查内核配置adb shell cat /proc/config.gz | gunzip | grep PSI备用方案启用vmpressure回退setprop lmkd.use_psi 05.3 性能优化案例某视频播放App后台被杀优化在AndroidManifest.xml添加application android:persistenttrue创建lmkd白名单echo com.example.video:200 /sys/module/lowmemorykiller/parameters/adj调整ADJ值需rootam set-standby-bucket com.example.video active6. 高级定制开发6.1 添加自定义策略在lmkd.cpp中添加策略模块// 自定义策略保护相机相关进程 static bool is_camera_protected(int pid) { char path[64], cmdline[256]; snprintf(path, sizeof(path), /proc/%d/cmdline, pid); if (read_file(path, cmdline, sizeof(cmdline)) 0) { return strstr(cmdline, camera) ! NULL; } return false; } // 修改kill逻辑 static int select_and_kill_process(int pressure_level) { ... if (is_camera_protected(p-pid)) { p-oomadj - 50; // 降低被杀概率 } ... }6.2 集成新版PSI监控Android 13新增的PSI聚合监控static void init_enhanced_psi() { struct epoll_event epev; int psi_fd open(/proc/pressure/memory_avg, O_RDONLY); epev.events EPOLLPRI; epev.data.fd psi_fd; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, psi_fd, epev); }6.3 厂商定制建议游戏模式优化// 当检测到游戏启动时 void on_game_mode_changed(bool enabled) { if (enabled) { set_min_score_adj(300); // 提高杀进程阈值 set_reclaim_pages(2048); // 增加单次回收量 } }内存压缩集成# 在杀进程前尝试zRAM压缩 echo 1 /sys/block/zram0/compact7. 测试验证方法7.1 自动化测试脚本import subprocess import time def test_lmkd_response(): # 分配内存直到触发LMKD alloc_mb 500 while True: proc subprocess.Popen([stress, f--vm-bytes {alloc_mb}M, --vm-keep -m 1]) time.sleep(1) log subprocess.check_output([logcat, -d, -s, lmkd]) if bKilling in log: proc.terminate() return True alloc_mb 1007.2 性能指标监控关键指标采集# 内存压力指数 adb shell cat /proc/pressure/memory # LMKD事件统计 adb shell dumpsys lmkd_stats # 进程生命周期记录 adb shell cat /data/system/lmkd/lmkd.log在分析厂商定制ROM时我发现某些实现会覆盖AOSP默认行为。例如某厂商的内存加速功能会动态调整minfree值这需要特别关注# 检测动态调整 adb shell watch -n 1 cat /sys/module/lowmemorykiller/parameters/minfree
阅读完成 · 觉得有帮助?