Try   HackMD

Android - Low Memory Killer

OverView of Content

概述

手機的設備,由於內存有限,若沒有處理好內存也會導致 OOM (Out Of Memory)

但是許多的程序都會有緩存機制(eg. Activity#finish 也不會立刻清除),這種機制是可以加快程序的啟動,減少反覆創建,不過相對來說就會一直佔用著內存

內存回收

Linux - OOMKiller

  • Linux 內核有自己的監控機制,就是 OOMKiller,在系統塊到達內存臨界點時 這個 OOM 的管理會自動跳出來清理背景程序(依照策不同會回收不同對象的記憶體)

  • 一般來說會依照優先順序,從最不重要的進程開始殺,當然也會考慮到以下幾點

    1. 進程消耗的內存
    2. 進程佔用的 CPU 時間
    3. oom_adj (OOM 權重)
  • Linux 可以透過 /proc(映射內存產生的數據,並不是真正資料) 資料夾查看對應的 oom_adj

    1. htop 查看 目前的程序的資訊,主要是要查 PID

    2. 接著查看 /proc/<PID\>/oom_adj & /proc/<PID\>/oom_score (score 越低則越晚被回收資源),下圖則代表 PID 為 8270 的程序不容易被回收

Android - Low Memory Killer (LMK)

  • Android 系統也是基於 Linux's OOMKiller 的核心思想,實現了不同階級的 Killer

  • Source code 在 / drivers / staging / android / lowmemorykiller.c,在初始化時會註冊一個 shrinker 回調,當記憶體到達臨界點時就會呼叫 lowmem_shrinker

// lowmemorykiller.c // 當記憶體到達臨界點時就會呼叫 lowmem_shrinker static struct shrinker lowmem_shrinker = { .shrink = lowmem_shrink, .seeks = DEFAULT_SEEKS * 16 }; static int __init lowmem_init(void) { register_shrinker(&lowmem_shrinker); // 註冊監聽 return 0; }
  • 等級 lowmem_adj & 閥值 lowmem_minfree,兩者是相互對應的,Eg. 當系統剩下 16 M 記憶體時,就會清理調 lowmem_adj 為 6 以上的進程(adj 的取值範圍是 -17~15,數字越小代表該進程的優先級別越高,越晚被回收)
static int lowmem_adj[6] = { // 默認 4 個 0, 1, 6, 12, }; static int lowmem_adj_size = 4; // 單位大小 static int lowmem_minfree[6] = { 3 * 512, /* 6MB */ // 512 * 3 * 4 = 6144 KB 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ 16 * 1024, /* 64MB */ };

  • 默認情況下,adj 會分為以下幾種
adj 值 描述 說明
15 HIDDEN_APP_MAX_AD 當前運行不可見的 aCTIVITY 進程
9 HIDDEN_APP_MIN_ADJ 同上
8 SERVICE_B_ADJ B list of srvice,與 A list 相比,他們對用戶的黏合更低
7 PREVIOUS_APP_ADJ 與用戶前一次互交的進程,也就上次一次使用的程序
6 HOME_APP_ADJ Launch 進程(桌面程序)
5 SERVCIE_ADJ 當前運行了 Application service 進程
4 BACK_UP_ADJ 專門於 backup 相關操作的進程
3 HEAVY_WEIGHT_APP_ADJ 重量級程序
2 PERCEPTIBLE_APP_ADJ 用戶可以感覺到,但是不可見到(後台運行)Eg. 音樂播放
1 VISIBLE_APP_ADJ 前台可見的 Activity 進程
0 FOREGROUND_APP_ADJ 當前正在使用(前台運行)的進程
-12 PERSISTENT_PROC_ADJ Persistent 進程,Eg. telephony
-16 SYTEM_ADJ 系統進程

調整 Android LMK 閥值

  • 上面有說到 lowmem_adj、owmem_adj_size 只是系統預設的數值,我們可以根據須修下去修改
  1. Android 系統提供了對應的文件讓我們修改

    ​​​​/sys/module/lowmemorykiller/parameters/adj ​​​​/sys/module/lowmemorykiller/parameters/minfree
    • 接下來可以在 init.rc 中加入設定
    ​​​​# 定義 0 & 8 ​​​​/sys/module/lowmemorykiller/parameters/adj 0, 8 ​​​​# 閥值 1M & 4M ​​​​/sys/module/lowmemorykiller/parameters/minfree 1024, 4096
  2. ActivityManagerService (AMS) 有一個 updateOomLevels 的函數,它的內部實現原理也是通過寫上面兩個文件來實現的

  • AMS 在運行時也會根據系統當前配置自動調整 adj & minfree 來適配不同的硬體
  1. AndroidMainfest 文件:添加 persistent=true 的屬性(要注意可能會引發系統無法回收記憶體的情況)

Appendix & FAQ

tags: Android 系統