古詩詞大全網 - 成語用法 - LowMemoryKiller機制分析

LowMemoryKiller機制分析

Linux系統當可用內存較低的時候oom killer機制會根據壹定的規則去殺掉壹些進程來釋放內存,而Android系統的LowMemoryKiller機制就是以此功能為基礎做了壹些調整。Android系統中的APP在使用完成之後並不會馬上被殺掉,而是駐留在內存中,當下壹次在此進入此應用的時候可以省去進程創建的過程,加快啟動速度。LowMemoryKiller機制會在內存資源緊張的時候,殺掉壹些進程來回收內存。

LowMemoryKiller機制分為三個部分

Framework中的ProcessList和Native的lmkd進程通過Socket進行進程間通信,而lmkd和內核中的LowMemoryKiller通過writeFileString向文件節點寫內容方法進行通信。

Framework層通過壹定的規則調整進程的adj的值和內存空間閥值,然後通過socket發送給lmkd進程,lmkd兩種處理方式, 壹種將閥值寫入文件節點發送給內核的LowMemoryKiller,由內核進行殺進程處理,另壹種是lmkd通過cgroup監控內存使用情況,自行計算殺掉進程。

lmkd是壹個native進程,由init進程啟動,定義在/system/core/lmkd/lmkd.rc中

在lmkd.rc中,啟動了lmkd進程,並創建了壹個名為lmkd的socket的描述符,用於socket進程間通信。lmkd啟動後首先執行main方法。

main方法首先設置了當前進程的調度規則,然後執行了init方法和mainLoop方法。

lmkd的init方法中做的工作

我們先分析內核實現的LowMemoryKiller進程查殺機制, 然後再分析lmkd實現的機制。兩者最終的結果都是在內存緊張的時候殺死壹些進程來釋放內存, 但是實現機制去不太壹樣。

init執行初始化完成之後, 進入mainloop方法,循環等待epoll事件的上報,init的時候epoll監聽的socket連接, 當有socket連接的時候就會調用ctrl_connect_handler方法。

監聽到socket連接, 我們知道此時連接lmkd的socket客戶端就是framework,當有連接到來的時候accept方法返回連接的socketFD, 然後將連接的socketFD同樣加入epoll中, 當socketFD中有可讀消息,即framework給lmkd發送消息的時候,epoll喚醒然後會掉ctrl_data_handler方法來處理。

Framework和lmkd進程通過socket來進行進程間通信,在lmkd初始化的時候,通過監聽socket描述符lmkd來等待Framework發送的消息。

Framework向lmkd發送命令相關的方法有三個。

上面的三種情況Framework最終是通過socket向lmkd發送了三種消息。

lmkd接收命令處理邏輯

lmkd通過epoll監聽socket中是否有數據, 當接受的framework發送的socket命令之後,調用ctrl_cmmand_handler方法處理,顯示解析socket中的命令和參數,根據對於的命令來調用不同的方法處理。

對於進程查殺有兩種實現方式,壹種是內核的LMK,通過shrinker來觸發低內存回收, 另壹種是lmkd通過cgroup監控內存使用情況,自行計算殺掉進程。兩種實現不太壹樣,需要逐個分析。

設置內存閥值和adj的值就是將從framework收到的數據封裝成字符串,通過writefilestring寫入到兩個文件節點,以供內核LMK使用。

/sys/module/lowmemorykiller/parameters/minfree : 內存級別限額

/sys/module/lowmemorykiller/parameters/adj :內存級別限額對應的要殺掉的進程的adj值.

由於使用內核LMK, 所以調整進程優先級直接將優先級寫入對應進程的oom_adj_score文件即可。

移除進程的時候不需要做任何操作

在linux中,有壹個名為kswapd的內核線程,當linux回收存放分頁的時候,kswapd線程將會遍歷壹張shrinker鏈表,並執行回調,或者某個app啟動,發現可用內存不足時,則內核會阻塞請求分配內存的進程分配內存的過程,並在該進程中去執行lowmemorykiller來釋放內存。雖然之前沒有接觸過,大體的理解就是向系統註冊了這個shrinker回調函數之後,當系統空閑內存頁面不足時會調用這個回調函數。 struct shrinker的定義在linux/kernel/include/linux/shrinker.h中:

內核LowMemoryKiller shrinker的註冊過程如下:

註冊完成之後, 在內存緊張的時候就會回調shrinker, 其中最主要的是lowmem_scan方法。具體實現如下:

內核LMK的原理很簡單:首先註冊了shrinker,在內存緊張的時候會觸發lowmem_scan方法,這個方法要做的就是找打壹個進程,然後殺掉他,釋放壹些內存。

內核LMK的實現邏輯已經分析完了

lmkd實現內存查實的方式是基於 cgroup memory 來實現的。

什麽是cgroup memory?

Cgroup的memory子系統,即memory cgroup(本文以下簡稱memcg),提供了對系統中壹組進程的內存行為的管理,從而對整個系統中對內存有不用需求的進程或應用程序區分管理,實現更有效的資源利用和隔離。

cgroup memory相關的文件

簡單的了解了下cgroup的原理,再來看lmkd的init方法

先了解下memory pressure_level的用法

init_mp_common方法嚴格的按照pressure_level的用法,註冊了pressure_level的事件回調, pressure_level分為三個等級

當內存達到相應的等級,就會回調mp_event_common方法, 由mp_event_common方法來處理。

lmkd內存查殺原理:

進程查殺的兩種實現方式原理類似,都是註冊是的回調,當內存緊張的時候根據剩余內存的adj來查殺大於該adj的內存。內核shrinker方式是只有內存緊張的時候才會去釋放,而cgroup方式控制更加精細, 根據不同等級來觸發內存回收。