1. 程式人生 > >Android對Linux核心的增強:Low Memory Killer(低記憶體管理)

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配置系統的相關引數。