新聞中心
Android 內(nèi)存管理原理
在Android開發(fā)中我們常常遇到app在后臺(tái)長(zhǎng)期不使用時(shí)被系統(tǒng)自動(dòng)回收掉,Android系統(tǒng)是怎么實(shí)現(xiàn)這個(gè)功能的呢。我們不討論如何讓app保活的方法,主要來(lái)說(shuō)說(shuō)系統(tǒng)實(shí)現(xiàn)這一機(jī)制的原理

為青海等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及青海網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、青海網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
在Android系統(tǒng)中使用oom_adj值來(lái)描述一個(gè)進(jìn)程的重要程度,它是AMS的Process類型中的一個(gè)變量,oom_adj值越小,表示進(jìn)程越重要,越不容易被殺掉。以下是AMS中定義的一些oom_adj值
可以看到一些運(yùn)行核心服務(wù)的進(jìn)程的oom_adj為-12(CORE_SERVER_ADJ),這類進(jìn)程基本不會(huì)被殺死。其他未賦值的都在static塊中進(jìn)行了初始化,是通過(guò)system/rootdir/init.rc進(jìn)行配置的:
可以看到前臺(tái)進(jìn)程的oom_adj值為0,這類進(jìn)程時(shí)我們正在交互的進(jìn)程,基本也不會(huì)被殺掉;空進(jìn)程對(duì)應(yīng)的值是15,當(dāng)系統(tǒng)內(nèi)存不足是最新殺掉的就是這類進(jìn)程(這類進(jìn)程一般指的是所有的activity都destory掉了,并且沒有service在運(yùn)行)。adj值下面描述的是各種內(nèi)存閥值。比如當(dāng)系統(tǒng)剩余內(nèi)存小于6144 * 4kb(ro.EMPTY_APP_MEM)是emty 進(jìn)程就會(huì)被回收掉。這些值對(duì)與每個(gè)手機(jī)廠商生產(chǎn)的手機(jī)都是不一樣的。以下是oom_adj值對(duì)應(yīng)的內(nèi)存閥值
如上所說(shuō),當(dāng)系統(tǒng)內(nèi)存小于6144 * 4kb時(shí)empty進(jìn)程將會(huì)被回收掉,而empty進(jìn)程的oom_adj值為15。在Activity、service、contentProvider、Broadcast Android四大組件的狀態(tài)的變化都會(huì)導(dǎo)致AMS更新對(duì)應(yīng)進(jìn)程oom_adj值,所以前臺(tái)進(jìn)程比后臺(tái)進(jìn)程更不容易殺掉,帶有service的后臺(tái)進(jìn)程比沒有service的進(jìn)程更不容易被殺掉
LMK的全稱是low memory killer,它是內(nèi)核的一個(gè)模塊。它里面保存了各個(gè)進(jìn)程的pid以及對(duì)應(yīng)的oom_adj,每次AMS調(diào)用updateOOmAdj函數(shù)更新進(jìn)程的oom_adj時(shí)都會(huì)通知LMK模塊。
LMK通過(guò)linux的shrinker模塊來(lái)監(jiān)聽系統(tǒng)的內(nèi)存變化,當(dāng)系統(tǒng)的剩余內(nèi)存達(dá)到某個(gè)閥值時(shí)就會(huì)殺掉oom_adj值大于這個(gè)閥值對(duì)應(yīng)的oom_adj的進(jìn)程。它會(huì)優(yōu)先殺掉內(nèi)存占用多的進(jìn)程,如果殺掉這些進(jìn)程內(nèi)存回到了正常值將不會(huì)繼續(xù)殺進(jìn)程。所以讓app不要占用大量的內(nèi)存也可以起到?;畹淖饔?/p>
Android App內(nèi)存優(yōu)化
內(nèi)存優(yōu)化就是對(duì)內(nèi)存問題的一個(gè)預(yù)防和解決,做內(nèi)存優(yōu)化能讓應(yīng)用掛得少、活得好和活得久。
掛的少:
“掛”指的是 Crash,內(nèi)存問題導(dǎo)致 Crash 的具體表現(xiàn)就是內(nèi)存溢出異常 OOM。
活得好:
活得好指的是使用流暢,Android 中造成界面卡頓的原因有很多種,其中一種就是由內(nèi)存問題引起的。內(nèi)存問題之所以會(huì)影響到界面流暢度,是因?yàn)槔厥眨℅C,Garbage Collection),在 GC 時(shí),所有線程都要停止,包括主線程,當(dāng) GC 和繪制界面的操作同時(shí)觸發(fā)時(shí),繪制的執(zhí)行就會(huì)被擱置,導(dǎo)致掉幀,也就是界面卡頓。
活得久:
活得久指的是我們的應(yīng)用在后臺(tái)運(yùn)行時(shí)不會(huì)被干掉。Android 會(huì)按照特定的機(jī)制清理進(jìn)程,清理進(jìn)程時(shí)優(yōu)先會(huì)考慮清理后臺(tái)進(jìn)程。清理進(jìn)程的機(jī)制就是LowMemoryKiller。在 Android 中不同的進(jìn)程有著不同的優(yōu)先級(jí),當(dāng)兩個(gè)進(jìn)程的優(yōu)先級(jí)相同時(shí),低殺會(huì)優(yōu)先考慮干掉消耗內(nèi)存更多的進(jìn)程。也就是如果我們應(yīng)用占用的內(nèi)存比其他應(yīng)用少,并且處于后臺(tái)時(shí),我們的應(yīng)用能在后臺(tái)活下來(lái),這也是內(nèi)存優(yōu)化為我們應(yīng)用帶來(lái)競(jìng)爭(zhēng)力的一個(gè)直接體現(xiàn)。
內(nèi)存占用是否越少越好?
當(dāng)系統(tǒng) 內(nèi)存充足 的時(shí)候,我們可以多用 一些獲得更好的性能。當(dāng)系統(tǒng) 內(nèi)存不足 的時(shí)候,我們希望可以做到 ”用時(shí)分配,及時(shí)釋放“。內(nèi)存優(yōu)化并不能一刀切。
我們都知道,應(yīng)用程序的內(nèi)存分配和垃圾回收都是由Android虛擬機(jī)完成的,在Android 5.0以下,使用的是Dalvik虛擬機(jī),5.0及以上,則使用的是ART虛擬機(jī)。
Android虛擬機(jī)Dalvik和ART
1、內(nèi)存區(qū)域劃分
詳細(xì)請(qǐng)看以下兩篇文章(建議全看):
java內(nèi)存四大區(qū)_JVM內(nèi)存區(qū)域劃分
Android 內(nèi)存機(jī)制
2、內(nèi)存回收
垃圾收集的標(biāo)記算法(找到垃圾):
垃圾收集算法(回收垃圾):
引用類型:強(qiáng)引用、軟引用、弱引用、虛引用
對(duì)象的有效性=可達(dá)性+引用類型
JAVA垃圾回收機(jī)制-史上最容易理解看這一篇就夠了
Android:玩轉(zhuǎn)垃圾回收機(jī)制與分代回收策略
android中還存在低殺機(jī)制,這種情況屬于系統(tǒng)整機(jī)內(nèi)存不足,直接把應(yīng)用進(jìn)程殺掉的情況。
Android后臺(tái)殺死系列:LowMemoryKiller原理
1、內(nèi)存溢出
系統(tǒng)會(huì)給每個(gè)App分配內(nèi)存空間也就是heap size值,當(dāng)app占用的內(nèi)存加上申請(qǐng)的內(nèi)存超過(guò)這個(gè)系統(tǒng)分配的內(nèi)存限額,最終導(dǎo)致OOM(OutOfMemory)使程序崩潰。
通過(guò)命令 getprop |grep dalvik.vm.heapsize 可以獲取系統(tǒng)允許的最大
注意:在設(shè)置了heapgrowthlimit的狀況下,單個(gè)進(jìn)程可用最大內(nèi)存為heapgrowthlimit值。在android開發(fā)中,若是要使用大堆,須要在manifest中指定android:largeHeap為true,這樣dvm heap最大可達(dá)heapsize。
關(guān)于heapsize heapgrowthlimit
2、內(nèi)存泄漏
Android系統(tǒng)虛擬機(jī)的垃圾回收是通過(guò)虛擬機(jī)GC機(jī)制來(lái)實(shí)現(xiàn)的。GC會(huì)選擇一些還存活的對(duì)象作為內(nèi)存遍歷的根節(jié)點(diǎn)GC Roots,通過(guò)對(duì)GC Roots的可達(dá)性來(lái)判斷是否需要回收。內(nèi)存泄漏就是 在當(dāng)前應(yīng)用周期內(nèi)不再使用的對(duì)象被GC Roots引用,造成該對(duì)象無(wú)法被系統(tǒng)回收,以致該對(duì)象在堆中所占用的內(nèi)存單元無(wú)法被釋放而造成內(nèi)存空間浪費(fèi),使實(shí)際可使用內(nèi)存變小。簡(jiǎn)言之,就是 對(duì)象被持有導(dǎo)致無(wú)法釋放或不能按照對(duì)象正常的生命周期進(jìn)行釋放。
Android常見內(nèi)存泄漏匯總
3、內(nèi)存抖動(dòng)
指的是在短時(shí)間內(nèi)大量的新對(duì)象被實(shí)例化,運(yùn)行時(shí)可能無(wú)法承載這樣的內(nèi)存分配,在這種情況下就會(huì)導(dǎo)致垃圾回收事件被大量調(diào)用,影響到應(yīng)用程序的UI和整體性能,最終可能導(dǎo)致卡頓和OOM。
常見情況:在一些被頻繁調(diào)用的方法內(nèi)不斷地創(chuàng)建對(duì)象。例如在View 的onDraw方法內(nèi)new 一些新的對(duì)象。
注意內(nèi)存抖動(dòng)也會(huì)導(dǎo)致 OOM,主要原因有如下兩點(diǎn):
1、Android Studio Profiler
作用
優(yōu)點(diǎn)
內(nèi)存抖動(dòng)問題處理實(shí)戰(zhàn)
理解內(nèi)存抖動(dòng)的概念的話,我們就能明白只要能找到抖動(dòng)過(guò)程中所產(chǎn)生的對(duì)象及其調(diào)用棧,我們就能解決問題,剛好Android Studio 的Porfiler里面的Memory工具就能幫我們記錄下我們操作過(guò)程中或靜止界面所產(chǎn)生的新對(duì)象,并且能清晰看到這些對(duì)象的調(diào)用棧。
選擇Profile 中 的Memory ,選擇 Record Java/Kotlin allocations,再點(diǎn)擊Record開始記錄, Record Java/Kotlin allocations 選項(xiàng)會(huì)記錄下新增的對(duì)象。
操作完成之后,點(diǎn)擊如圖所示的紅腦按鈕,停止記錄。
停止記錄后,我們就可以排序(點(diǎn)擊 Allocations可以排序)看看哪些對(duì)象或基本類型在短時(shí)間被頻繁創(chuàng)建多個(gè),點(diǎn)擊這些新增的對(duì)象就可以看到它的完成的調(diào)用鏈了,進(jìn)而就找找到導(dǎo)致內(nèi)存抖動(dòng)的地方在哪里了。
2、利用DDMS 和 MAT(Memory Analyzer tool)來(lái)分析內(nèi)存泄漏
我們利用工具進(jìn)行內(nèi)存泄漏分析主要是用對(duì)比法:
a.先打開正常界面,不做任何操作,先抓取一開始的堆文件。
b.一頓胡亂操作,回到原來(lái)操作前的界面。主動(dòng)觸發(fā)一兩次GC,過(guò)10秒再抓取第二次堆文件。
c.通過(guò)工具對(duì)比,獲取胡亂操作后新增的對(duì)象,然后分析這些新增的對(duì)象。
DDMS作用:抓取堆文件,主動(dòng)觸發(fā)GC。(其實(shí)也是可以用Android Studio 的Profile里面的Memory工具來(lái)抓取堆文件的,但是我這邊在利用Profile 主動(dòng)觸發(fā)gc 的時(shí)候會(huì)導(dǎo)致程序奔潰,也不知道是不是手機(jī)的問題,所以沒用Android Studio的Profiler)
MAT作用:對(duì)堆文件進(jìn)行對(duì)比,找到多出的對(duì)象,找到對(duì)象的強(qiáng)引用調(diào)用鏈。
以下是詳細(xì)的過(guò)程:
步驟1.打開DDMS,選擇需要調(diào)試的應(yīng)用,打開初始界面,點(diǎn)擊下圖的圖標(biāo)(Dump Hprof File)先獲取一次堆文件。
步驟2.對(duì)應(yīng)用隨便操作后,回到一開始的界面,先多觸發(fā)幾次GC ,點(diǎn)擊下圖的圖標(biāo)(Cause Gc)來(lái)主動(dòng)觸發(fā)GC,然后再次點(diǎn)擊 Dump Hprof File 圖標(biāo)來(lái)獲取堆文件。
步驟3.通過(guò)Android Studio Profile 或者 DDMS dump 的堆文件無(wú)法在MAT 打開,需要借助android sdk包下的一個(gè)工具h(yuǎn)prof-conv.exe來(lái)轉(zhuǎn)換。
格式為 hprof-conv 舊文件路徑名 要轉(zhuǎn)換的名稱;
例如:hprof-conv 2022-04-13_17-54-40_827.hprof change.hprof
步驟4.把兩份堆文件導(dǎo)入MAT,然后選擇其中第二次獲取的堆文件,點(diǎn)擊 如圖所示的 Histogram查看。
步驟5.點(diǎn)擊下圖圖標(biāo),Compare To Another Heap Dump ,選擇另一份堆文件。
6.會(huì)得出下圖所示的 Hitogram 展示,我們主要看Objects 這一列。 如下圖所示 “+ 2” 則代表前面兩份堆文件對(duì)比,這個(gè)對(duì)象多了兩個(gè),我們主要就是要分析這些多了出來(lái),沒有被回收的對(duì)象。
7.加入我們從增加的對(duì)象中,看到了MainActivity ,則需要從一開始打開的Hitogram 展示里面找到這個(gè)對(duì)象的調(diào)用棧。如下圖所示,搜索MainActivity
8.看到下圖所示解雇,然后鼠標(biāo)右鍵點(diǎn)擊下圖紅色圈圈著的MainActivity ,選擇 Merger Shortest Paths to Gc Roots ,再選擇 exclude all phantom/weak/soft etc.references ,就可以看到這個(gè)MainActivity 對(duì)象的強(qiáng)引用鏈,至此我們就可以找到MainActivity對(duì)象是被什么引用導(dǎo)致無(wú)法回收了。
3、內(nèi)存泄露檢測(cè)神器之LeakCanary(線下集成)
自行學(xué)習(xí)了解,接入簡(jiǎn)單,使用簡(jiǎn)單,基本可以解決大部分內(nèi)存泄漏問題。
github地址 :
學(xué)習(xí)地址 :
針對(duì)內(nèi)存抖動(dòng)的建議:
針對(duì)內(nèi)存泄漏問題的建議:
針對(duì)內(nèi)存溢出問題的建議(主要就是要減少內(nèi)存占用):
建議參考:
深入探索 Android 內(nèi)存優(yōu)化(煉獄級(jí)別)
對(duì)于 優(yōu)化的大方向,我們應(yīng)該優(yōu)先去做見效快的地方,主要有以下三部分:內(nèi)存泄漏、內(nèi)存抖動(dòng)、Bitmap。完善監(jiān)控機(jī)制也是我們的重點(diǎn),能幫助我們對(duì)內(nèi)存問題快速分析和處理。
參考:
深入探索 Android 內(nèi)存優(yōu)化(煉獄級(jí)別)
Android手機(jī)清理內(nèi)存的方法
和PC用戶一樣智能手機(jī)用戶也會(huì)遇到手機(jī)存儲(chǔ)不足的問題,對(duì)于Android手機(jī)來(lái)說(shuō)因?yàn)橄到y(tǒng)不支持安裝程序到SD卡,手機(jī)配置的存儲(chǔ)容量也有限,很多用戶都碰到過(guò)安裝程序太多系統(tǒng)內(nèi)存不足的問題。雖然Android2.2系統(tǒng)開始已經(jīng)支持Apps2SD功能,但是很多用戶使用后發(fā)現(xiàn)Android2.2系統(tǒng)下仍然有很多應(yīng)用程序無(wú)法安裝到SD卡,即可程序支持移動(dòng)到SD卡,但是還會(huì)保留一部分系統(tǒng)文件和隱私文件在手機(jī)內(nèi)存里。另外還有一些程序像Widgets,動(dòng)態(tài)壁紙和一些系統(tǒng)程序,如果安裝在SD卡根本無(wú)法正常工作,內(nèi)存不足依然是讓很多用戶感到棘手的問題。不過(guò)Android作為一種優(yōu)秀的移動(dòng)操作系統(tǒng),提供了幾種可以清理和釋放內(nèi)存空間的辦法,我們總結(jié)了下面幾點(diǎn)希望可以幫助用戶解決燃眉之急。
清理大型應(yīng)用程序的緩存數(shù)據(jù)。
1、通過(guò)清理程序的緩存文件,釋放的內(nèi)存空間會(huì)讓你喜出望外。 2、進(jìn)入手機(jī)設(shè)置選項(xiàng),選擇設(shè)置應(yīng)用程序管理應(yīng)用程序。 3、按一下Menu鍵,選擇“按大小排序”選項(xiàng)(如果是Android2.2手機(jī)先要選擇已下載標(biāo)簽),然后就可以按照應(yīng)用程序大小排列所有手機(jī)安裝的應(yīng)用程序。 4、點(diǎn)擊一款列表中的應(yīng)用程序,如果程序有緩存文件可以顯示大小,直接點(diǎn)擊“清除緩存”選項(xiàng)就可以釋放這些緩存文件占據(jù)的空間。 5、有一些應(yīng)用程序的緩存文件可能多達(dá)數(shù)MB,比如GoogleMaps,Market,瀏覽器和相冊(cè)程序,清理這幾個(gè)程序的緩存文件就可以釋放相當(dāng)可觀的空間。 6、很多手機(jī)廠商都在旗下手機(jī)預(yù)裝了自己開發(fā)的UI程序,比如HTCSense,MOTOBLUR等,如果你打算使用LaunherPro或者ADW這樣的launcher程序替代HTCSense,你可以清理甚至刪除HTCSense的數(shù)據(jù)文件,這個(gè)操作可以讓你的'手機(jī)多出幾十MB空間。 7、另外AndroidMarket還提供一些自動(dòng)清除緩存文件的應(yīng)用程序,比如QuickAppCleanCache這款收費(fèi)軟件。對(duì)于已經(jīng)取得root權(quán)限的手機(jī)用戶,可以從Market下載CacheCleaner,CacheMate和MoveCache這些程序來(lái)快速方便的清除程序緩存文件。
刪除那些你從來(lái)不用或者很少使用的應(yīng)用程序這是很多用戶都會(huì)面對(duì)的問題,默默忍受著手機(jī)內(nèi)存不足的報(bào)警,甚至犧牲系統(tǒng)性能,就是舍不得刪除那些從來(lái)不用或者極少使用的應(yīng)用程序,這可能也是一種強(qiáng)迫癥。刪除這些程序你會(huì)發(fā)現(xiàn)手機(jī)從此海闊天空,而且你沒有任何損失。移動(dòng)所以可以移動(dòng)的應(yīng)用程序數(shù)據(jù)到SD卡運(yùn)行Android2.2系統(tǒng)的手機(jī)支持安裝應(yīng)用程序到SD卡,確保檢查所有你安裝的應(yīng)用程序如果支持appstoSD卡功能一定要移動(dòng)到SD卡,對(duì)于一些大型軟件特別是游戲程序節(jié)省的容量相當(dāng)可觀。
不過(guò)一定要注意Widgets程序,捆綁Widgets的程序,以及動(dòng)態(tài)壁紙程序和那些需要在后臺(tái)運(yùn)行并且和系統(tǒng)進(jìn)行交互的應(yīng)用程序不要移動(dòng)到SD卡存儲(chǔ),否則程序可能無(wú)法正常工作。如果覺得每個(gè)程序單獨(dú)設(shè)置太麻煩,可以借助Apps2SD和SDMove這樣的程序簡(jiǎn)化操作過(guò)程。對(duì)于那些動(dòng)手能力比較強(qiáng)的用戶可以通過(guò)網(wǎng)上的教程設(shè)置應(yīng)用程序默認(rèn)安裝到SD卡,這樣就可以一勞永逸。
Android系統(tǒng)內(nèi)存管理
部分內(nèi)容出至林學(xué)森的Android內(nèi)核設(shè)計(jì)思想。
Android官網(wǎng)內(nèi)存管理
部分出至
Android本質(zhì)是Linux所以先從Linux說(shuō)起。
Linux的內(nèi)存管理為系統(tǒng)中所有的task提供可靠的內(nèi)存分配、釋放和保護(hù)機(jī)制。
核心:
虛擬內(nèi)存
內(nèi)存分配與釋放
內(nèi)存保護(hù)
將外存儲(chǔ)器的部分空間作為內(nèi)存的擴(kuò)展,如從硬盤劃出4GB大小。
當(dāng)內(nèi)存資源不足時(shí),系統(tǒng)按照一定算法自動(dòng)條形優(yōu)先級(jí)低的數(shù)據(jù)塊,并把他們存儲(chǔ)到硬盤中。
后續(xù)如果需要用到硬盤中的這些數(shù)據(jù)塊,系統(tǒng)將產(chǎn)生“缺頁(yè)”指令,然后把他們交換回內(nèi)存中。
這些都是由操作系統(tǒng)內(nèi)核自動(dòng)完成的,對(duì)上層應(yīng)用”完全透明“。
每個(gè)進(jìn)程的邏輯地址和物理地址都不是直接對(duì)應(yīng)的,任何進(jìn)程都沒辦法訪問到它管轄范圍外的內(nèi)存空間——即刻意產(chǎn)生的內(nèi)存越界與非法訪問,操作系統(tǒng)也會(huì)馬上阻止并強(qiáng)行關(guān)閉程序,從而有力的保障應(yīng)用程序和操作系統(tǒng)的安全和穩(wěn)定。
一旦發(fā)現(xiàn)系統(tǒng)的可用內(nèi)存達(dá)到臨界值,機(jī)會(huì)按照優(yōu)先級(jí)順序,匆匆低到高逐步殺掉進(jìn)程,回收內(nèi)存。
存儲(chǔ)位置:/proc/PID/oom_score
優(yōu)先級(jí)策略:
進(jìn)程消耗的內(nèi)存
進(jìn)程占用的CPU時(shí)間
oom_adj(OOM權(quán)重)
Android平臺(tái)運(yùn)行的前提是可用內(nèi)存是浪費(fèi)的內(nèi)存。它試圖在任何時(shí)候使用所有可用的內(nèi)存。例如,系統(tǒng)會(huì)在APP關(guān)閉后將其保存在內(nèi)存中,以便用戶可以快速切換回它們。出于這個(gè)原因,Android設(shè)備通常運(yùn)行時(shí)只有很少的空閑內(nèi)存。在重要系統(tǒng)進(jìn)程和許多用戶應(yīng)用程序之間正確分配內(nèi)存內(nèi)對(duì)存管理是至關(guān)重要。
Android有兩種主要的機(jī)制來(lái)處理低內(nèi)存的情況:內(nèi)核交換守護(hù)進(jìn)程(kernel swap daemon)和低內(nèi)存殺手(low-memory killer)。
當(dāng)用戶在APP之間切換時(shí),Android會(huì)在最近使用的(LRU)緩存中保留不在前臺(tái)的APP,即用戶看不到的APP,或運(yùn)行類似音樂播放的前臺(tái)服務(wù)。如果用戶稍后返回APP,系統(tǒng)將重用該進(jìn)程,從而使APP切換更快。
如果你的APP有一個(gè)緩存進(jìn)程,并且它保留了當(dāng)前不需要的內(nèi)存,那么即使用戶不使用它,你的APP也會(huì)影響系統(tǒng)的整體性能。由于系統(tǒng)內(nèi)存不足,它會(huì)從最近使用最少的進(jìn)程開始?xì)⑺繪RU緩存中的進(jìn)程。該系統(tǒng)還負(fù)責(zé)處理占用最多內(nèi)存的進(jìn)程,并可以終止這些進(jìn)程以釋放RAM。
當(dāng)系統(tǒng)開始終止LRU緩存中的進(jìn)程時(shí),它主要是自底向上工作的。系統(tǒng)還考慮哪些進(jìn)程消耗更多的內(nèi)存,從而在終止時(shí)為系統(tǒng)提供更多的內(nèi)存增益。你在LRU列表中消耗的內(nèi)存越少,你就越有可能留在列表中并能夠快速恢復(fù)。
為了滿足RAM的所有需求,Android嘗試共享RAM來(lái)跨進(jìn)程通信。它可以做到以下方式:
Android設(shè)備包含三種不同類型的內(nèi)存:RAM、zRAM和storage。
注意:CPU和GPU都訪問同一個(gè)RAM。
內(nèi)存被拆分成頁(yè)。通常每頁(yè)有4KB的內(nèi)存。
頁(yè)面被認(rèn)為是空閑的或已使用的。
空閑頁(yè)是未使用的RAM。
已使用頁(yè)是系統(tǒng)正在積極使用的RAM,分為以下類別:
干凈的頁(yè)面(Clean pages)包含一個(gè)文件(或文件的一部分)的一份精確副本存在存儲(chǔ)器上。當(dāng)一個(gè)干凈的頁(yè)面不再包含一個(gè)精確的文件副本(例如,來(lái)自應(yīng)用程序操作的結(jié)果)時(shí),它就變成了臟頁(yè)??梢詣h除干凈的頁(yè),因?yàn)樗鼈兪冀K可以使用存儲(chǔ)中的數(shù)據(jù)重新生成;不能刪除臟頁(yè)(Dirty pages),否則數(shù)據(jù)將丟失。
內(nèi)核跟蹤系統(tǒng)中的所有內(nèi)存頁(yè)。
當(dāng)確定一個(gè)應(yīng)用程序正在使用多少內(nèi)存時(shí),系統(tǒng)必須考慮shared pages。APP訪問相同的服務(wù)或庫(kù)將可能共享內(nèi)存頁(yè)。例如,Google Play Services 和一個(gè)游戲APP可能共享一個(gè)位置服務(wù)。這使得很難確定有多少內(nèi)存屬于這個(gè)服務(wù)相對(duì)于每個(gè)APP。
當(dāng)操作系統(tǒng)想要知道所有進(jìn)程使用了多少內(nèi)存時(shí),PSS非常有用,因?yàn)轫?yè)面不會(huì)被多次計(jì)數(shù)。PSS需要很長(zhǎng)時(shí)間來(lái)計(jì)算,因?yàn)橄到y(tǒng)需要確定哪些頁(yè)面是共享的,以及被有多少進(jìn)程。RSS不區(qū)分共享頁(yè)面和非共享頁(yè)面(使計(jì)算速度更快),更適合于跟蹤內(nèi)存分配的更改。
內(nèi)核交換守護(hù)進(jìn)程(kswapd)是Linux內(nèi)核的一部分,它將使用過(guò)的內(nèi)存轉(zhuǎn)換為空閑內(nèi)存。當(dāng)設(shè)備上的空閑內(nèi)存不足時(shí),守護(hù)進(jìn)程將變?yōu)榛顒?dòng)狀態(tài)。Linux內(nèi)核保持低和高的可用內(nèi)存閾值。當(dāng)空閑內(nèi)存低于低閾值時(shí),kswapd開始回收內(nèi)存。當(dāng)空閑內(nèi)存達(dá)到高閾值,kswapd將停止回收內(nèi)存。
kswapd可以通過(guò)刪除干凈的頁(yè)面來(lái)回收干凈的頁(yè)面,因?yàn)樗鼈冇写鎯?chǔ)器支持并且沒有被修改。如果進(jìn)程試圖尋址已刪除的干凈頁(yè),則系統(tǒng)會(huì)將該頁(yè)從存儲(chǔ)器復(fù)制到RAM。此操作稱為請(qǐng)求分頁(yè)。
kswapd將緩存的私有臟頁(yè)(private dirty pages)和匿名臟頁(yè)(anonymous dirty pages)移動(dòng)到zRAM進(jìn)行壓縮。這樣做可以釋放RAM中的可用內(nèi)存(空閑頁(yè))。如果進(jìn)程試圖觸摸zRAM中臟頁(yè),則該頁(yè)將被解壓縮并移回RAM。如果與壓縮頁(yè)關(guān)聯(lián)的進(jìn)程被終止,則該頁(yè)將從zRAM中刪除。
如果可用內(nèi)存量低于某個(gè)閾值,系統(tǒng)將開始終止進(jìn)程。
lmkd實(shí)現(xiàn)源碼要在system/core/lmkd/lmkd.c。
lmkd會(huì)創(chuàng)建名為lmkd的socket,節(jié)點(diǎn)位于/dev/socket/lmkd,該socket用于跟上層framework交互。
小結(jié):
LMK_TARGET: AMS.updateConfiguration() 的過(guò)程中調(diào)用 updateOomLevels() 方法, 分別向/sys/module/lowmemorykiller/parameters目錄下的minfree和adj節(jié)點(diǎn)寫入相應(yīng)信息;
LMK_PROCPRIO: AMS.applyOomAdjLocked() 的過(guò)程中調(diào)用 setOomAdj() 向/proc/pid/oom_score_adj寫入oom_score_adj后直接返回;
LMK_PROCREMOVE: AMS.handleAppDiedLocked 或者 AMS.cleanUpApplicationRecordLocked() 的過(guò)程,調(diào)用remove(),目前不做任何事,直接返回;
為了進(jìn)一步幫助平衡系統(tǒng)內(nèi)存并避免終止APP進(jìn)程,可以Activity類中實(shí)現(xiàn)ComponentCallbacks2接口。提供的onTrimMemory()回調(diào)方法允許APP在前臺(tái)或后臺(tái)偵聽與內(nèi)存相關(guān)的事件,然后釋放對(duì)象以響應(yīng)應(yīng)用程序生命周期或表明系統(tǒng)需要回收內(nèi)存的系統(tǒng)事件。
onTrimMemory()回調(diào)是在Android 4.0(API級(jí)別14)中添加的。
對(duì)于早期版本,可以使用onLowMemory(),它大致相當(dāng)于TRIM_MEMORY_COMPLETE事件。
一個(gè)專門的驅(qū)動(dòng)。(Linux Kernel 4.12 已移除交給kswapd處理)。
很多時(shí)候,kswapd無(wú)法為系統(tǒng)釋放足夠的內(nèi)存。在這種情況下,系統(tǒng)使用onTrimMemory()通知APP內(nèi)存不足,應(yīng)該減少其分配。如果這還不夠,內(nèi)核將開始終止進(jìn)程以釋放內(nèi)存,它使用低內(nèi)存殺手(LMK)來(lái)完成這個(gè)任務(wù)。
為了決定要終止哪個(gè)進(jìn)程,LMK使用一個(gè)名為oom_adj_score的“out of memory”分?jǐn)?shù)來(lái)確定運(yùn)行進(jìn)程的優(yōu)先級(jí),高分的進(jìn)程首先被終止。
后臺(tái)應(yīng)用程序首先被終止,系統(tǒng)進(jìn)程最后被終止。
下表列出了從高到低的LMK評(píng)分類別。第一排得分最高的項(xiàng)目將首先被殺死:
Android Runtime(ART)和Dalvik虛擬機(jī)使用分頁(yè)(Paging)和內(nèi)存映射(mmapping)來(lái)管理內(nèi)存。應(yīng)用程序通過(guò)分配新對(duì)象或觸摸已映射頁(yè)面來(lái)修改內(nèi)存都將保留在RAM中,并且不能被調(diào)出。應(yīng)用程序釋放內(nèi)存的唯一方式是垃圾收集器。
網(wǎng)頁(yè)標(biāo)題:android內(nèi)存,android內(nèi)存優(yōu)化
標(biāo)題路徑:http://www.dlmjj.cn/article/hocjph.html


咨詢
建站咨詢
