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。前者存放着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配置系統的相關參數。