Android LMK(Low Memory Killer)机制

在 Android 系统中,LMK (Low Memory Killer) 是内存管理的"最后一道防线"。它的核心任务是在系统内存不足时,按照优先级倒序杀掉进程,以保证系统核心服务的运行和用户当前正在使用的应用(Foreground App)的流畅性。

作为 Android 13/AAOS 开发者,理解 LMK 的工作原理能帮你更好地优化车载应用的生命周期管理。

LMK 日志 lowmemorykiller

yaml 复制代码
M01EECC  12-25 14:53:54.854   326   326 I lowmemorykiller: Kill 'com.xxx.xxxx' (1538), uid 1000, oom_score_adj 107 to free 111348kB rss, 60552kB swap; reason: <swap is extremely low (124936kB < 125152kB)>

1. 核心机制:oom_score_adj 评分系统

Android 为每个进程分配了一个重要性评分,称为 oom_score_adj(取值范围 -1000 到 1000)。分值越高,进程越容易被 LMK 杀掉。

系统根据应用当前的状态动态更新这个分值:

进程状态 oom_score_adj (近似值) 描述
Native/System -1000 绝对不能杀掉的核心进程(如 init, system_server)。
Persistent -700 ~ -800 声明了 persistent 的系统应用。
Foreground 0 当前用户正在交互的应用进程。
Visible 100 ~ 200 用户可见但不在前台(如分屏应用、被透明 Activity 覆盖的应用)。
Perceptible 200 用户能感知到的应用(如正在播放音乐、有前台 Service)。
Cached / Background 900 ~ 1000 已经退到后台且没有任务的应用。最先被清理

2. 进化:从内核到用户态 (lmkd)

  • 传统方式 (Kernel LMK): 早期 Android 使用 Linux 内核驱动程序。它根据系统剩余内存(Free Memory)是否达到预设的"水位线"(Minfree)来触发杀进程逻辑。

  • 现代方式 (Userspace lmkd): 从 Android 9.0 开始,核心逻辑移到了用户空间守护进程 lmkd

    • Android 13 默认使用 lmkd
    • 它不再只看"剩余内存",而是看 PSI (Pressure Stall Information)

3. LMK 的触发流程:基于 PSI 的压力检测

在 Android 13/AAOS 中,lmkd 通过监控内核提供的 PSI 来评估系统压力。PSI 会告诉系统: "因为内存不足,任务等待 CPU 或 IO 的时间占比是多少?"

  1. 监控 (Monitoring): lmkd 监听内核的 PSI 事件。

  2. 压力分级:

    • Low Pressure: 内存稍微紧张,开始杀掉一些 oom_score_adj 非常高的 Cached 应用。
    • Medium Pressure: 压力增大,杀掉普通的后台应用。
    • Critical Pressure: 极度危险,甚至可能杀掉不直接可见的 Service 进程,以防止 UI 卡死。
  3. 选择目标 (Selection): 寻找当前 oom_score_adj 最大的进程。如果分数相同,通常杀掉内存占用更大的。

  4. 执行 (Kill): lmkd 发送 SIGKILL 信号强制结束进程。


4. 车载 (AAOS) 环境下的特殊性

在车载项目(如你提到的一汽大众项目)中,LMK 的调优比手机更敏感:

  • 倒车影像/全景 (Safety First): 涉及泊车等安全功能的进程通常会设置极低的 oom_score_adj,甚至会被设为 persistent,确保在任何情况下都不会被 LMK 干掉。
  • 多显示器 (Multi-Display): 即使 App 在副屏运行,它也属于 VisibleForeground 级别,oom_score_adj 会比普通后台应用低,受 LMK 保护。
  • 资源竞争: 车机系统往往长时间不重启,且会有大量的 B-Call、E-Call、导航等后台 Service。如果你在启动一个重型 App(如高清电影平台)前手动清理,确实能有效延迟 PSI 达到 Critical 阈值的时间,从而避免系统因瞬间内存剧增导致其他关键组件闪退。

5. 解决方案:

  • 在应用层方面

如果拥有系统签名文件,可以添加配置 sharedUserIdpersistent

ini 复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:sharedUserId="android.uid.system">
    
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:persistent="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:directBootAware="true"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Launcher">

    </application>

</manifest>
  • 在 Framework 方面

adb shell 查看是否配置白名单:

bash 复制代码
/vendor/etc/lmkd_param.conf

在这个目录 Framework 目录下添加要保护的包名,配置白名单

bash 复制代码
./device/sprd/mpool/module/vendor/memory/lmkd/msoc/qogirn6pro/lmkd_param.conf

6. 调试工具

如果你想观察实时的 LMK 行为,可以使用以下命令:

  • 查看当前各进程得分:

    Bash

    复制代码
    adb shell ps -Ao pid,args,oomscore
  • 查看 lmkd 日志:

    Bash

    perl 复制代码
    adb logcat | grep lmkd
    # 你会看到类似 "Kill 'com.android.app' (PID), adj 900, to free 150MB" 的日志

建议: 可以结合 ActivityManager.getMyMemoryState() 或监听 onTrimMemory() 回调。如果系统已经回调了 TRIM_MEMORY_RUNNING_CRITICAL,说明 LMK 已经在"磨刀"了,此时主动释放资源或清理后台是最佳时机。

相关推荐
andr_gale18 小时前
04_rc文件语法规则
android·framework·aosp
祖国的好青年19 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
黄林晴19 小时前
警惕!AGP 9.2 别只改版本号,R8 规则与构建链路全线收紧
android·gradle
小米渣的逆袭19 小时前
Android ADB 完全使用指南
android·adb
儿歌八万首19 小时前
Jetpack Compose Canvas 进阶:结合 animateFloatAsState 让自定义图形动起来
android·动画·compose
zhangphil20 小时前
Android Page 3 Flow读sql数据库媒体文件,Kotlin
android·kotlin
神探小白牙21 小时前
echarts,3d堆叠图
android·3d·echarts
李白的天不白21 小时前
如何项目发布到github上
android·vue.js
summerkissyou198721 小时前
Android-RTC、NTP 和 System Time(系统时间)
android