Android對Linux核心的增強:Low Memory Killer(低記憶體管理)
Android在記憶體管理上與linux有些小的區別。其中一個就是引入了Low memory killer .
1,引入原因
Android是一個多工系統,也就是說可以同時執行多個程式,這個大家應該很熟悉。一般來說,啟動執行一個程式是有一定的時間開銷的,因此為了加快執行速度,當你退出一個程式時,Android並不會立即殺掉它,這樣下次再執行該程式時,可以很快的啟動。隨著系統中保留的程式越來越多,記憶體肯定會出現不足,low memory killer就是在系統記憶體低於某值時,清除相關的程式,保障系統保持擁有一定數量的空閒記憶體。
2,基本原理和重要概念
Low memory killer根據兩個原則,程序的重要性和釋放這個程序可獲取的空閒記憶體數量,來決定釋放的程序。
(1)程序的重要性,由task_struct->signal_struct->oom_adj決定。
Android將程式分成以下幾類,按照重要性依次降低的順序:
名稱 oom_adj 解釋
FOREGROUD_APP 0 前臺程式,可以理解為你正在使用的程式
VISIBLE_APP 1 使用者可見的程式
SECONDARY_SERVER 2 後臺服務,比如說QQ會在後臺執行服務
HOME_APP 4 HOME,就是主介面
HIDDEN_APP 7 被隱藏的程式
CONTENT_PROVIDER 14 內容提供者,
EMPTY_APP
15
空程式,既不提供服務,也不提供內容
其中每個程式都會有一個oom_adj值,這個值越小,程式越重要,被殺的可能性越低。
(2)程序的記憶體,通過get_mm_rss獲取,在相同的oom_adj下,記憶體大的,優先被殺。
(3)那記憶體低到什麼情況下,low memory killer開始幹活呢?Android提供了兩個陣列,一個lowmem_adj,一個lowmem_minfree。www.linuxidc.com前者存放著oom_adj的閥值,後者存放著minfree的警戒值,以page為單位(4K)。
oom_adj 記憶體警戒值( 以4K為單位)
0 1536
1 2048
2 4096
7 5120
14 5632
15 6144
3,原始碼解析
module_init(lowmem_init);
module_exit(lowmem_exit);
模組載入和退出的函式,主要的功能就是register_shrinker和unregister_shrinker結構體lowmem_shrinker。主要是將函式lowmem_shrink註冊到shrinker連結串列裡,在mm_scan呼叫。
下面詳細的介紹這個函式:
for (i = 0; i < array_size; i++) {
if (other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
break;
}
}
other_file,系統的空閒記憶體數,根據上面的邏輯判斷出,low memory killer需要對adj高於多少(min_adj)的程序進行分析是否釋放。
if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
lowmem_print(5, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
return rem;
}
判斷,系統當前的狀態是否需要進行low memory killer。
for_each_process(p) {
struct mm_struct *mm;
struct signal_struct *sig;
int oom_adj;
task_lock(p);
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
task_unlock(p);
continue;
}
oom_adj = sig->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
}
對每個sig->oom_adj大於min_adj的程序,找到佔用記憶體最大的程序存放在selected中。
if (selected) {
if (fatal_signal_pending(selected)) {
pr_warning("process %d is suffering a slow death\n",
selected->pid);
read_unlock(&tasklist_lock);
return rem;
}
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}
傳送SIGKILL資訊,殺掉該程序。
4,配置
通過下面兩個檔案,/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller /parameters/minfree配置系統的相關引數。