Android Native 之 lmkd进程和kernel kswapd的关联

发布于:2025-06-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

lwkd进程属于native层启动的一个守护进程,他的作用贯穿android世界的始终。他的另外一个大家都属于的名字lowmemorykiller。

根据readme的介绍lmkd是用来对android系统内存检查的守护进程,它通过终止不重要的进程来达到系统稳定运行的状态。在Linux Kernel 4.12之前是这项任务是放在了kernel进行管理,在Linux Kernel 4.12之后移到了native层中,因为在kernel进程管理中直接干掉某个应用进程太过暴力。

后面介绍了我们可以通过一些属性的值来控制lmkd进程的效果,如下:

  • ro.config.low_ram: choose between low-memory vs high-performance device. Default = false.

  • ro.lmk.use_minfree_levels: use free memory and file cache thresholds for making decisions when to kill. This mode works the same way kernel lowmemorykiller driver used to work. Default = false

  • ro.lmk.low: min oom_adj score for processes eligible to be killed at low vmpressure level. Default = 1001 (disabled)

  • ro.lmk.medium: min oom_adj score for processes eligible to be killed at medium vmpressure level. Default = 800 (non-essential processes)

  • ro.lmk.critical: min oom_adj score for processes eligible to be killed at critical vmpressure level. Default = 0 (all processes)

  • ro.lmk.critical_upgrade: enables upgrade to critical level. Default = false

  • ro.lmk.upgrade_pressure: max mem_pressure at which level will be upgraded because system is swapping too much. Default = 100 (disabled)

  • ro.lmk.downgrade_pressure: min mem_pressure at which vmpressure event will be ignored because enough free memory is still available. Default = 100 (disabled)

  • ro.lmk.kill_heaviest_task: kill heaviest eligible task (best decision) vs. any eligible task (fast decision). Default = false

  • ro.lmk.kill_timeout_ms: duration in ms after a kill when no additional kill will be done. Default = 0 (disabled)

  • ro.lmk.debug: enable lmkd debug logs, Default = false

  • ro.lmk.swap_free_low_percentage: level of free swap as a percentage of the total swap space used as a threshold to consider the system as swap space starved. Default for low-RAM devices = 10, for high-end devices = 20

  • ro.lmk.thrashing_limit: number of workingset refaults as a percentage of the file-backed pagecache size used as a threshold to consider system thrashing its pagecache. Default for low-RAM devices = 30, for high-end devices = 100

  • ro.lmk.thrashing_limit_decay: thrashing threshold decay expressed as a percentage of the original threshold used to lower the threshold when system does not recover even after a kill. Default for low-RAM devices = 50, for high-end devices = 10

  • ro.lmk.psi_partial_stall_ms: partial PSI stall threshold in milliseconds for triggering low memory notification. Default for low-RAM devices = 200, for high-end devices = 70

  • ro.lmk.psi_complete_stall_ms: complete PSI stall threshold in milliseconds for triggering critical memory notification. Default = 700

lmkd will set the following Android properties according to current system configurations:

  • sys.lmk.minfree_levels: minfree:oom_adj_score pairs, delimited by comma

  • sys.lmk.reportkills: whether or not it supports reporting process kills to clients. Test app should check this property before testing low memory kill notification. Default will be unset.

一、LMKD源码分析

1、LMKD进程的启动

1.1 三种启动方式

同其他native进程一致,他的启动还是通过init rc机制来启动。如下代码

总结如下:

  • 标记为core类的服务会在init.rcon early-initon init阶段被启动,未显式设置disabled属性时,core类服务会随init进程初始化自动启动。PS:在core进行启动是为了防止核心服务没有启动导致系统异常
  • 监听sys.boot_completed开机属性然后传递--reinit参数进行完整启动。PS:从后文可以了解到reinit会去读取一系列相关属性,即这是完整启动
  • 最后监听属性变更,传递--reinit参数,应该是做成不需要重启系统就能够动态生效这些参数的效果

1.2 主函数三部曲

二、Kernel kswapd线程分析

kernel_platform/msm-kernel/mm/page_alloc.c 是 Linux 内核中负责‌物理页帧分配与管理‌的核心实现文件,主要功能如下:

一、核心功能

  1. 伙伴系统(Buddy System)

    • 实现alloc_pages()/free_pages()等接口,通过2^n阶页块管理物理内存13
    • 处理内存碎片合并与拆分(如__free_one_page()函数)3
  2. 页分配策略

    • 控制GFP标志(GFP_KERNEL/GFP_ATOMIC等)的分配行为14
    • 实现水位线(WMARK_MIN/WMARK_LOW)和内存回收触发逻辑3
  3. NUMA架构支持

    • 多节点内存分配(__alloc_pages_nodemask()

二、关键代码结构

函数/宏 功能说明
__alloc_pages_nodemask 分配页帧的核心逻辑(含慢速路径/快速路径)3
get_page_from_freelist 从空闲列表获取可用页帧3
zone_watermark_ok 检查内存水位是否满足分配需求3
__free_pages_ok 释放页帧到伙伴系统3

三、与lmkd的关联

lmkd触发内存回收时,最终会通过该文件中的分配器获取/释放物理页帧24。例如:

  • GFP_KERNEL分配可能触发直接内存回收(__perform_reclaim
  • 低内存时通过__alloc_pages_slowpath进入回收流程3

注:该文件是内存管理子系统(MM)的核心组件,代码路径通常为/mm/page_alloc.c,MSM内核版本会包含高通平台的特定优化13。

__setup_per_zone_wmarks这个函数是干什么的?

__setup_per_zone_wmarks是Linux内核中用于初始化内存管理区(zone)水位线(watermark)的关键函数,其核心功能如下:

一、核心作用

  1. 计算并设置三档水位值

    • 根据min_free_kbytes全局参数,为每个zone动态计算WMARK_MIN(最低警戒线)、WMARK_LOW(kswapd唤醒线)、WMARK_HIGH(kswapd休眠线)14
    • 默认比例关系:LOW = MIN * 5/4HIGH = MIN * 3/246
  2. NUMA架构适配

    • 针对不同内存节点(node)的zone独立计算水位,考虑局部内存特性

二、水位线的作用机制

水位等级 触发行为
WMARK_HIGH 内存充足,kswapd线程进入休眠状态69
WMARK_LOW 空闲内存低于此值,唤醒kswapd进行异步回收57
WMARK_MIN 触发直接内存回收(direct reclaim),可能阻塞进程分配请求

三、典型调用流程

  1. 系统启动时通过init_per_zone_wmark_min()调用该函数4
  2. 根据公式计算每个zone的min_free_kbytes分摊值:zonemin=min_free_kbytes×zonesizetotal_non_highmem_pageszonemin​=total_non_highmem_pagesmin_free_kbytes×zonesize​​再基于此值推导其他水位

四、相关代码逻辑

// mm/page_alloc.c static void __setup_per_zone_wmarks(void) { // 计算各zone的min水位 for_each_zone(zone) { zone->watermark[WMARK_MIN] = calc_min_watermark(zone); // 推导low/high水位 zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + (tmp >> 2); zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1); } }

该函数是内存分配器(如get_page_from_freelist)判断是否触发回收的核心依据