LowMemoryKiller是Android 系統在Linux kernel的OOMKiller基礎上打的一個補丁。OOMKiller在kernel 無法再分配內存的時候,尋找一個得分最高的進程來殺掉。LowMemoryKiller則提早一步,經過把剩餘內存劃分紅不一樣的級別,內存在消耗的過程當中,觸發不一樣的級別,殺死相應的app進程。在觸發OOMKiller前,大量緩存的app進程已經被殺死掉了。java
先簡單說一下OOMKiller。android
咱們查看任一進程的proc信息(如:/proc/1), 都會看到如下三個參數:算法
所以,用戶設置oom_adj後,kernel會轉換並更新該進程實際的oom_score_adj值,它們的換算關係是:數組
#define OOM_DISABLE (-17) #define OOM_SCORE_ADJ_MAX 1000 oom_score_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; oom_adj = (oom_score_adj * - OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
從上面能夠看到,這個算法是有損的,因此,有時候會發現讀出的oom_adj的值同設置得不同了。如,設置oomajd=13, 那麼 oom_score_adj=764,再次讀oom_adj, 764 * 17 / 1000 == 12了。緩存
當內存耗盡的時候,OOMKiller會調用 out_of_memory()來select_bad_process(), oom_score最大的值就是那個將要被殺死的bad process。 oom_badness()以oom_score_adj做爲基礎值,根據是否爲管理員進程,佔用的內存狀況,來計算出最終的oom_score值,分值越高,越容易被殺死。app
OOMKiller相應的源碼文件:socket
/fs/proc/base.c /mm/oom_kill.c
在Android系統裏面,當app的狀態發生變化,如:建立,收到廣播,喚醒,放入後臺等, ActivityManagerService的updateOomAdjLocked() 會computeOomAdjLocked(),而後,經過applyOomAdjLocked()把app的oom_adj值寫入到Linux Kernel。函數
那麼AN是如何計算每一個app最終的oom_adj值的呢?工具
咱們知道oom_adj的範圍是[-16, 15],AN根據app進程的特性進行了分類,不一樣的類別,對應不一樣的數值。網站
LowMemoryKiller註冊了shrinker--Linux Kernel的一個內存管理工具,當kernel須要回收內存時,會回調LowMemoryKiller的lowmem_shrink(),它先檢查kernel 剩下多少內存,根據剩下的內存數量來匹配數組 lowmem_minfree[], 找到數組索引值,而後,再使用該索引值,從 lowmem_adj[]這個數組裏面就獲得目標oom_adj值,最終,在大於等於該目標oom_adj的進程中,殺死擁有最大oom_adj值的進程--send_sig(SIGKILL, selected, 0) 。算法其實很簡單,就是兩個一維數組的映射。
static short lowmem_adj[6] = { 0, 1, 6, 12, }; static int lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ };
如: 系統剩下的內存爲 31024, 它 小於 4 1024,對應的數組索引是 2, lowmem_adj[2]對應的是 6,那麼系統將在oom_adj>=6的進程中,找一個最大的oom_adj的進程,而後,殺死它釋放內存。
Android在初始化的時候,會經過ProcessList::updateOomLevels()來設定上面兩個數組的初始值,咱們能夠經過framework的config.xml,或 /sys文件系統接口進行調整lowmem_minfree []。
/sys/module/lowmemorykiller/parameters/minfree <integer name="config_lowMemoryKillerMinFreeKbytesAbsolute">-1</integer> <integer name="config_lowMemoryKillerMinFreeKbytesAdjust">0</integer>
config_....KbytesAbsolute:非-1的狀況下,是絕對值, AN使用下面算法,獲得實際數組值。
for ( int i = 0 ; i < mOomAdj.length; i++) { mOomMinFree[ i ] = (int) ((float)minfree_abs * mOomMinFree[ i ] / mOomMinFree[ mOomAdj.length - 1 ] ); }
config_....KbytesAdjust: 非0狀況下, 直接在每一個數組值上 += reserve_adj;
如: <integer name="config_....KbytesAdjust">-512</integer>,代表每一個數組值都減小512。
lowmem_adj[] 能夠經過/sys 文件系統接口來進行調整。
/sys/module/lowmemorykiller/parameters/adj
固然了在實際上開發過程當中,也能夠直接在這個函數裏面打補丁,或者讀取系統屬性,經過屬性來進行配置等等。 像MStar方案,就定義了兩個屬性來進行第三方的配置: ro.mstar.lmkd.minfree和ro.mstar.lmkd.adj
到這裏,基本上LowMemoryKiller算是說完了,最後,簡單介紹下,AN是如何把oom_adj值傳給kernel的。
AN經過ProcessList:setOomAdj(),用socket與lmkd通信, lmkd經過/sys文件系統接口,把oom_adj值傳遞給LinuxKernel。
/sys/module/lowmemorykiller/parameters/minfree /sys/module/lowmemorykiller/parameters/adj
相關的源碼文件分別在:
system/core/lmkd/ 生成 /system/bin/lmkd drivers/staging/android/lowmemorykiller.c framework/base/...../server/am/
歡迎你們來個人網站交流:般若程序蟬:prajna.top