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 已经在"磨刀"了,此时主动释放资源或清理后台是最佳时机。

相关推荐
时光呀时光慢慢走2 小时前
MAUI 开发安卓 MQTT 客户端:实现远程控制 (完整源码 + 避坑指南)
android·物联网·mqtt·c#
成都大菠萝3 小时前
2-2-44 快速掌握Kotlin-函数类型操作
android
有位神秘人3 小时前
Android中获取设备里面的音频文件
android
2501_915918414 小时前
使用 HBuilder 上架 iOS 应用时常见的问题与应对方式
android·ios·小程序·https·uni-app·iphone·webview
farewell-Calm4 小时前
01_Android快速入门
android
helloCat5 小时前
记录CI/CD自动化上传AppGallery遇到的坑
android·前端·api
WordPress学习笔记5 小时前
wordpress根据页面别名获取该页面的链接
android·wordpress
2501_916007476 小时前
iOS 崩溃日志的分析方法,将崩溃日志与运行过程结合分析
android·ios·小程序·https·uni-app·iphone·webview
浅箬6 小时前
Taro3的H5项目在Android、IOS 中因为兼容性问题导致的白屏问题
android·团队开发·taro