Android 內(nèi)存管理

Android系統(tǒng)是基于Linux 2.6內(nèi)核開發(fā)的開源操作系統(tǒng),而linux系統(tǒng)的內(nèi)存管理有其獨(dú)特的動態(tài)存儲管理機(jī)制。
不過Android系統(tǒng)對Linux的內(nèi)存管理機(jī)制進(jìn)行了優(yōu)化,Linux系統(tǒng)會在進(jìn)程活動停止后就結(jié)束該進(jìn)程,而Android把這些進(jìn)程都保留在內(nèi)存中,直到系統(tǒng)需要更多內(nèi)存為止。這些保留在內(nèi)存中的進(jìn)程通常情況下不會影響整體系統(tǒng)的運(yùn)行速度,并且當(dāng)用戶再次激活這些進(jìn)程時,提升了進(jìn)程的啟動速度。

Android內(nèi)存管理包含兩部分,一部分是Framework對內(nèi)存的管理,一部分是Linux內(nèi)核對內(nèi)存管理,這兩部分共同決定應(yīng)用程序的生命周期。

在Android中,大部分應(yīng)用程序都運(yùn)行在一個獨(dú)立的Linux進(jìn)程中,每個進(jìn)程都有獨(dú)立的內(nèi)存空間。隨著各種應(yīng)用程序啟動,系統(tǒng)內(nèi)存不斷下降,為了保證新應(yīng)用能夠運(yùn)行,Android需要一套機(jī)制殺死暫時閑置的進(jìn)程。

Android Framework并不能直接回收內(nèi)存,其管理進(jìn)程的服務(wù)(ActivityManagerService,以下簡稱AmS)也同應(yīng)用程序一樣運(yùn)行在Java虛擬機(jī)環(huán)境里。Java虛擬機(jī)都運(yùn)行在各自獨(dú)立的內(nèi)存空間,所以ActivityManagerService沒有辦法感知應(yīng)用程序是否OOM。

Android系統(tǒng)中還運(yùn)行了一個OOM進(jìn)程。該進(jìn)程啟動時首先會在Linux內(nèi)核中把自己注冊為一個OOM Killer。AmS需要把每一個應(yīng)用程序的oom_adj值告知OOM Killer,這個值的范圍在-16到15之間,值越低,說明越重要,這個值類似于Linux中的nice值,只在標(biāo)準(zhǔn)的Linux中,有其自己的OOM Killer。Android中的OOM Killer進(jìn)程僅僅適用于Android應(yīng)用程序。

當(dāng)內(nèi)核的內(nèi)存管理模塊檢測到系統(tǒng)內(nèi)存不足時就會通知OOM Killer,然后OOM Killer根據(jù)AmS所告知的優(yōu)先級強(qiáng)制退出優(yōu)先級低的應(yīng)用程序。

Android 內(nèi)存管理機(jī)制

基于Linux內(nèi)核OOM Killer的核心思想,Android 系統(tǒng)擴(kuò)展出了自己的內(nèi)存監(jiān)控體系。因?yàn)長inux下的內(nèi)存殺手需要等到系統(tǒng)資源”瀕臨絕境”的情況下才會產(chǎn)生效果。
而Android則實(shí)現(xiàn)了自己的Killer。Android 系統(tǒng)為此開發(fā)了一個專門的驅(qū)動,名為Low Memory Killer(LMK)。源碼路徑在內(nèi)核工程的drivers/staging/android/Lowmemorykiller.c中。

它的驅(qū)動加載函數(shù)如下:

static int __init lowmem_init(void)
{
    register_shrinker(&lowmem_shrinker);
    return 0;
}

當(dāng)系統(tǒng)的空閑頁面低于一定閾值時,這個回調(diào)就會被執(zhí)行。

Lowmemorykiller.c 中定義了兩個數(shù)組,分別如下:

static short lowmem_adj[6] = {
    0,
    1,
    6,
   12,
 };
static int lowmem_adj_size = 4;//下面的數(shù)值以此為單位(頁大小)
static int lowmem_minfree[6] = {
    3 * 512,    /* 6MB */
    2 * 1024,   /* 8MB */
    4 * 1024,   /* 16MB */
    16 * 1024,  /* 64MB */
};
  • 第一個數(shù)組lowmem_adj最多有6個元素,默認(rèn)只定義了4個,它表示可用容量處于”某層級”時需要被處理的adj值;

  • 第二個數(shù)組則是對”層級”的描述。舉個例子,lowmem_minfree 的第一個元素是3*512*lowmem_adj_size=6MB,意味著當(dāng)可用內(nèi)存小于6MB時,Killer需要清理adj的值為0(即lowmem_adj的第一個元素)以下的那些進(jìn)程。其中adj的取值范圍是-17~15,數(shù)字越小表示進(jìn)程級別越高,通常只有0-15被使用。

android進(jìn)程優(yōu)先級

android將進(jìn)程的優(yōu)先級分為5個層次,按照優(yōu)先級由高到低排列如下:

  1. 前臺進(jìn)程(Foreground process):它表明用戶正在與該進(jìn)程進(jìn)行交互操作,android系統(tǒng)依據(jù)下面的條件來將一個進(jìn)程標(biāo)記為前臺進(jìn)程:
  • 該進(jìn)程持有一個用戶正在與其交互的Activity(也就是這個activity的生命周期方法走到了onResume()方法)。
  • 該進(jìn)程持有一個Service,并且這個Service與一個用戶正在交互中的Activity進(jìn)行綁定。
  • 該進(jìn)程持有一個前臺運(yùn)行模式的Service(也就是這個Service調(diào)用了startForegroud()方法)。
  • 該進(jìn)程持有一個正在執(zhí)行生命周期方法(onCreate()、onStart()、onDestroy()等)的Service。
  • 該進(jìn)程持有一個正在執(zhí)行onReceive()方法的BroadcastReceiver。
    一般情況下,不會有太多的前臺進(jìn)程。殺死前臺進(jìn)程是操作系統(tǒng)最后無可奈何的做法。當(dāng)內(nèi)存嚴(yán)重不足的時候,前臺進(jìn)程一樣會被殺死。
  1. 可見進(jìn)程(Visible process):它表明雖然該進(jìn)程沒有持有任何前臺組件,但是它還是能夠影響到用戶看得到的界面。android系統(tǒng)依據(jù)下面的條件將一個進(jìn)程標(biāo)記為可見進(jìn)程:
  • 該進(jìn)程持有一個非前臺Activity,但這個Activity依然能被用戶看到(也就是這個Activity調(diào)用了onPause()方法)。例如,當(dāng)一個activity啟動了一個對話框,這個activity就被對話框擋在后面。
  • 該進(jìn)程持有一個與可見(或者前臺)Activity綁定的Service。
  1. 服務(wù)進(jìn)程(Service process):除了符合前臺進(jìn)程和可見進(jìn)程條件的Service,其它的Service都會被歸類為服務(wù)進(jìn)程。

  2. 后臺進(jìn)程(Background process):持有不可見Activity(調(diào)用了onStop()方法)的進(jìn)程即為后臺進(jìn)程。通常情況下都會有很多后臺進(jìn)程,當(dāng)內(nèi)存不足的時候,在所有的后臺進(jìn)程里面,會按照LRU(最近使用)規(guī)則,優(yōu)先回收最長時間沒有使用過的進(jìn)程。

  3. 空進(jìn)程(Empty process):不持有任何活動組件的進(jìn)程。保持這種進(jìn)程只有一個目的,就是為了緩存,以便下一次啟動該進(jìn)程中的組件時能夠更快響應(yīng)。當(dāng)資源緊張的時候,系統(tǒng)會平衡進(jìn)程緩存和底層的內(nèi)核緩存情況進(jìn)行回收。

前臺>可見>服務(wù)>后臺>空

如果一個進(jìn)程同時滿足上述5種優(yōu)先級中的多個等級條件,android系統(tǒng)會優(yōu)先選取其中最高的等級作為該進(jìn)程的優(yōu)先級。

內(nèi)存管理機(jī)制的特點(diǎn)

  1. 更少的占用內(nèi)存;
  2. 在合理的時候,合理的釋放內(nèi)存;
  3. 在系統(tǒng)內(nèi)存緊張的情況下,能釋放大部分不重要的的資源,來為Android提供可用的資源;
  4. 能夠很合理的在特殊生命周期中,保存和回復(fù)還原重要數(shù)據(jù),以至于系統(tǒng)能夠正確的重新恢復(fù)該應(yīng)用。

一些內(nèi)存優(yōu)化的方法

  1. 當(dāng)Service完成任務(wù)后,盡量停止它,或者用intentService代替;
  2. 在UI不可見的時候,釋放掉一些只有UI使用的資源;
  3. 在系統(tǒng)資源內(nèi)存緊張的時候,盡可能多的釋放掉一些非重要資源;
  4. 避免濫用Bitmap導(dǎo)致的內(nèi)存浪費(fèi),參見Here
  5. 使用針對內(nèi)存優(yōu)化過的數(shù)據(jù)容器
  6. 避免使用依賴注入的框架
  7. 使用ZIP對其APK
  8. 使用多進(jìn)程

參考并感謝

  1. Android內(nèi)存管理機(jī)制詳解
  2. Android 內(nèi)存管理機(jī)制詳解
  3. Android 內(nèi)存優(yōu)化總結(jié)&實(shí)踐
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android是一個基于Linux實(shí)現(xiàn)的操作系統(tǒng)。但對于Linux內(nèi)核來說,Android也僅僅只是一個運(yùn)行在內(nèi)核...
    Gooooood閱讀 3,516評論 1 15
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,234評論 25 708
  • 一.操作系統(tǒng)相關(guān)基礎(chǔ)知識 1.物理內(nèi)存、虛擬內(nèi)存、邏輯地址與交換空間 物理內(nèi)存(RAM):加載到內(nèi)存地址寄存器中的...
    Geeks_Liu閱讀 9,502評論 6 31
  • 先看看百度 1842年,英國物理學(xué)家Earnshaw就提出了磁懸浮的概念,同時指出:單靠永久磁鐵是不能將一個鐵磁體...
    我要去拉薩閱讀 975評論 0 1
  • 從朕登基,最討厭的就是做周報(bào)。一周五天,周一開會,周五做周報(bào)。朕哪還有時間處理政事,寵幸愛妃。 直到用了matpl...
    胖兔123閱讀 1,053評論 0 0

友情鏈接更多精彩內(nèi)容