1. 程式人生 > >Android記憶體程序管理,Low Memory Killer機制

Android記憶體程序管理,Low Memory Killer機制

當我們要退出一個程序時只能按返回鍵,而該程序並沒有真正的關閉,程序依然是存在於記憶體之中.這樣設計的目的是為了下次能快速啟動.當然,隨著系統執行時間的增長,記憶體會越來越少,所以系統會定期執行一次檢查,清理一些程序,釋放掉記憶體.這就是Android的Low Memory Killer機制

在kernel/drivers/staging/android/路徑下的lowmemorykiller.c檔案定義了lowmem_adj和lowmem_minfree兩個陣列,一個是adj 陣列,描述process 所對應的oom_adj,另外一個是minfree陣列,描述process 所對應的memory 的閾值,程式碼如下(Android6.0):

static short lowmem_adj[6] = {
    0,
    1,
    6,
    12,
};
static int lowmem_adj_size = 4;
static int lowmem_minfree[6] = {
    3 * 512,    /* 6MB */
    2 * 1024,   /* 8MB */
    4 * 1024,   /* 16MB */
    16 * 1024,  /* 64MB */
};
  • Low Memory Killer在使用者空間中指定了一組記憶體臨界值,當其中的某個值與程序描述中的oom_adj值在同一範圍時,該程序將被Kill掉
  • Android中的oom相關引數在init.rc中進行初始化配置,在系統執行時由ActivityManagerService進行動態調整。

當記憶體達到對應閥值時會按優先順序清理對應閥值的程序

檢視系統閥值: adb shell cat /sys/module/lowmemorykiller/parameters/minfree

C:\Users\admin>adb shell cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,55296,80640
以上數字的單位是page. 1 page = 4 kb
對應的就是(MB
)
: 72,90,108,216,216,315

OOM_ADJ優先順序分類 原始碼路徑: repo/frameworks/base/services/core/java/com/android/server/am/ProcessList.java

// OOM adjustments for processes in various states:

    // Adjustment used in certain places where we don't know it yet.
    // (Generally this is something that is going to be cached, but we
    // don't know the exact value in the cached range to assign yet.)
    static final int UNKNOWN_ADJ = 16;

    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption.
    static final int CACHED_APP_MAX_ADJ = 15;
    static final int CACHED_APP_MIN_ADJ = 9;

    // The B list of SERVICE_ADJ -- these are the old and decrepit
    // services that aren't as shiny and interesting as the ones in the A list.
    static final int SERVICE_B_ADJ = 8;

    // This is the process of the previous application that the user was in.
    // This process is kept above other things, because it is very common to
    // switch back to the previous app.  This is important both for recent
    // task switch (toggling between the two top recent apps) as well as normal
    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
    // and then pressing back to return to e-mail.
    static final int PREVIOUS_APP_ADJ = 7;

    // This is a process holding the home application -- we want to try
    // avoiding killing it, even if it would normally be in the background,
    // because the user interacts with it so much.
    static final int HOME_APP_ADJ = 6;

    // This is a process holding an application service -- killing it will not
    // have much of an impact as far as the user is concerned.
    static final int SERVICE_ADJ = 5;

    // This is a process with a heavy-weight application.  It is in the
    // background, but we want to try to avoid killing it.  Value set in
    // system/rootdir/init.rc on startup.
    static final int HEAVY_WEIGHT_APP_ADJ = 4;

    // This is a process currently hosting a backup operation.  Killing it
    // is not entirely fatal but is generally a bad idea.
    static final int BACKUP_APP_ADJ = 3;

    // This is a process only hosting components that are perceptible to the
    // user, and we really want to avoid killing them, but they are not
    // immediately visible. An example is background music playback.
    static final int PERCEPTIBLE_APP_ADJ = 2;

    // This is a process only hosting activities that are visible to the
    // user, so we'd prefer they don't disappear.
    static final int VISIBLE_APP_ADJ = 1;

    // This is the process running the current foreground app.  We'd really
    // rather not kill it!
    static final int FOREGROUND_APP_ADJ = 0;

    // This is a process that the system or a persistent process has bound to,
    // and indicated it is important.
    static final int PERSISTENT_SERVICE_ADJ = -11;

    // This is a system persistent process, such as telephony.  Definitely
    // don't want to kill it, but doing so is not completely fatal.
    static final int PERSISTENT_PROC_ADJ = -12;

    // The system process runs at the default adjustment.
    static final int SYSTEM_ADJ = -16;

    // Special code for native processes that are not being managed by the system (so
    // don't have an oom adj assigned by the system).
    static final int NATIVE_ADJ = -17;

Android將程序分為6個等級,foreground(前臺程序)、visible(可見程序)、secondary server(次要服務)、hidden(後臺程序)、content provider(內容供應節點)、empty(空程序)
- 前臺程序(FOREGROUND_APP):目前正在螢幕上顯示的程序和一些系統程序

- 可見程序(VISIBLE_APP):可見程序是一些不在前臺,但使用者依然可見的程序,它和FOREGROUND_APP的區別是使用者沒有focus的程式,但是使用者看得到

- 次要服務(SECONDARY_SERVER):目前正在執行的所有服務不包括系統服務

- 後臺程序(HIDDEN_APP):指後臺程序(background)是指前臺程序或可見程序退到後臺了

- 內容供應節點(CONTENT_PROVIDER):沒有程式實體,僅提供內容供別的程式去用的

- 空程序(EMPTY_APP):沒有任何東西在內執行的程序,在程式退出後,依然會在程序中駐留一個空程序,這個程序裡沒有任何資料在執行,作用往往是提高該程式下次的啟動速度或者記錄程式的一些歷史資訊

APP動態分配堆記憶體

VMRuntime.getRuntime().setMinimumHeapSize(NewSize); 堆(HEAP)是VM中佔用記憶體最多的部分,通常是動態分配的。堆的大小不是一成不變的,通常有一個分配機制來控制它的大小。比如初始的HEAP是4M大,當4M的空間被佔用超過75%的時候,重新分配堆為8M大;當8M被佔用超過75%,分配堆為16M大。倒過來,當16M的堆利用不足30%的時候,縮減它的大小為8M大。重新設定堆的大小,尤其是壓縮,一般會涉及到記憶體的拷貝,所以變更堆的大小對效率有不良影響