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.rc
的on early-init
或on 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 內核中負責?物理頁幀分配與管理?的核心實現文件,主要功能如下:
一、核心功能
-
?伙伴系統(Buddy System)?
- 實現
alloc_pages()
/free_pages()
等接口,通過2^n階頁塊管理物理內存13 - 處理內存碎片合并與拆分(如
__free_one_page()
函數)3
- 實現
-
?頁分配策略?
- 控制
GFP
標志(GFP_KERNEL
/GFP_ATOMIC
等)的分配行為14 - 實現水位線(
WMARK_MIN/WMARK_LOW
)和內存回收觸發邏輯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)的關鍵函數,其核心功能如下:
一、核心作用
-
?計算并設置三檔水位值?
- 根據
min_free_kbytes
全局參數,為每個zone動態計算WMARK_MIN
(最低警戒線)、WMARK_LOW
(kswapd喚醒線)、WMARK_HIGH
(kswapd休眠線)14 - 默認比例關系:
LOW = MIN * 5/4
,HIGH = MIN * 3/2
46
- 根據
-
?NUMA架構適配?
- 針對不同內存節點(node)的zone獨立計算水位,考慮局部內存特性
二、水位線的作用機制
水位等級 | 觸發行為 |
---|---|
?WMARK_HIGH? | 內存充足,kswapd線程進入休眠狀態69 |
?WMARK_LOW? | 空閑內存低于此值,喚醒kswapd進行異步回收57 |
?WMARK_MIN? | 觸發直接內存回收(direct reclaim),可能阻塞進程分配請求 |
三、典型調用流程
- 系統啟動時通過
init_per_zone_wmark_min()
調用該函數4 - 根據公式計算每個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
)判斷是否觸發回收的核心依據