--- title: 'Android - Low Memory Killer' disqus: kyleAlien --- Android - Low Memory Killer === ## OverView of Content [TOC] ## 概述 手機的設備,由於內存有限,若沒有處理好內存也會導致 OOM (Out Of Memory) 但是許多的程序都會有緩存機制(eg. Activity#finish 也不會立刻清除),這種機制是可以加快程序的啟動,減少反覆創建,不過相對來說就會一直佔用著內存 ## 內存回收 ### Linux - OOMKiller * Linux 內核有自己的監控機制,就是 **OOMKiller**,在系統塊到達內存臨界點時 這個 OOM 的管理會自動跳出來清理背景程序(依照策不同會回收不同對象的記憶體) * 一般來說會依照優先順序,從最不重要的進程開始殺,當然也會考慮到以下幾點 1. 進程消耗的內存 2. 進程佔用的 CPU 時間 3. oom_adj (OOM 權重) * Linux 可以透過 **[/proc(映射內存產生的數據,並不是真正資料)](https://hackmd.io/MtOap5UaR7KcJpdTisc75g?view#%E8%B3%87%E6%96%99%E5%A4%BE%E4%BB%8B%E7%B4%B9)** 資料夾查看對應的 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** ```c= // 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,數字越小代表該進程的優先級別越高,越晚被回收) ```c= 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 系統提供了對應的文件讓我們修改 ```shell= /sys/module/lowmemorykiller/parameters/adj /sys/module/lowmemorykiller/parameters/minfree ``` 接下來可以在 **init.rc** 中加入設定 ```shell= # 定義 0 & 8 /sys/module/lowmemorykiller/parameters/adj 0, 8 # 閥值 1M & 4M /sys/module/lowmemorykiller/parameters/minfree 1024, 4096 ``` 2. ActivityManagerService (AMS) 有一個 updateOomLevels 的函數,它的內部實現原理也是通過寫上面兩個文件來實現的 :::success * AMS 在運行時也會根據系統當前配置自動調整 adj & minfree 來適配不同的硬體 ::: 3. AndroidMainfest 文件:添加 persistent=true 的屬性(要注意可能會引發系統無法回收記憶體的情況) ## Appendix & FAQ :::info ::: ###### tags: `Android 系統`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up