Activity管理(二):adj內(nèi)存管理機(jī)制

*本文主要介紹Android的lowmemorykiller的oom_adj的相關(guān)概念蔬蕊,以及根據(jù)一些案例來闡述了解oom_adj對于做Android應(yīng)用開發(fā)的重要意義麻献。*

*一、lowmeorykiller中進(jìn)程的分類以及各類進(jìn)程的adj值*

? *在Android的lowmemroykiller機(jī)制中齿桃,會對于所有進(jìn)程進(jìn)行分類短纵,對于每一類別的進(jìn)程會有其oom_adj值的取值范圍香到,oom_adj值越高則代表進(jìn)程越不重要悠就,在系統(tǒng)執(zhí)行低殺操作時梗脾,會從oom_adj值越高的開始?xì)ⅰ?*******系統(tǒng)lowmemeorykiller機(jī)制下對于進(jìn)程的級別的以變量的形式定義在framework/base/core/java/com/android/server/am/ProcessList.java類中藐唠,可總結(jié)成下表:*

[外鏈圖片轉(zhuǎn)存中...(img-Ad1ffcK0-1612332903000)]

*再補(bǔ)充介紹一下:*

*1.AMS角度對于進(jìn)程的分級*

*上表帶分級只是從lowmemroykiller角度來分的鹉究,時用于lowmemeorykiller執(zhí)行殺進(jìn)程操作自赔,但是從android的系統(tǒng)管理角度看,即是從AMS執(zhí)行相關(guān)邏輯時润脸,又有一套自己的分級機(jī)制他去,當(dāng)然這兩套機(jī)制也有著很多互通的點(diǎn)灾测。AMS角度的級別劃分以變量的形式定義在framework/base/core/java/android/app/ActivityManager.java類中,以PROCESS_STATE開頭的變量铭段。*

*2.沒有stopService其內(nèi)含activity的后臺進(jìn)程*

? *這類進(jìn)程從lowmemorykiller角度是劃分為cached序愚,因?yàn)槿绻@類進(jìn)程往往占有較大的內(nèi)存,這類含有activity的后臺進(jìn)程往往占有較大內(nèi)存芬膝,所以即使這類進(jìn)程包含了Service蔗候,lowmemorykiller的機(jī)制也會更加傾向于優(yōu)先殺死這類進(jìn)程埂软。*

? *但是一般啟動了服務(wù)的進(jìn)程往往是希望服務(wù)在后臺能夠執(zhí)行某些任務(wù)勘畔,這樣看是不希望這些服務(wù)因?yàn)檫M(jìn)程被殺而過早的被終止的炫七,那如何調(diào)和這種矛盾呢钾唬?正確的做法是,對于期望較長時間留在后臺的服務(wù)奕巍,應(yīng)該將服務(wù)運(yùn)行在單獨(dú)的進(jìn)程里的止,即是UI進(jìn)程與Servie進(jìn)程分離着撩,這樣期望長時間留在后臺的Serivce會存在與一個被lmk分類為Service 進(jìn)程的服務(wù)而獲得較小的Adj值,而占有大量內(nèi)存的UI進(jìn)程則會分類為Cached進(jìn)程氓润,能夠在需要的時候更快地被回收咖气。*

? *還有一點(diǎn),這類進(jìn)程雖然被lmk劃分為cached進(jìn)程运嗜,但是從ams角度是被劃分為PROCESS_STATE_SERVICE這個類別的,即視為服務(wù)進(jìn)程奋救,在ams相關(guān)流程中也是以服務(wù)進(jìn)程來執(zhí)行相關(guān)邏輯的反惕,此外在使用dumpsys meminfo查看所有進(jìn)程時,這類進(jìn)程也是被列在B service這個類別的背亥。*

*3.A-Service與B-Service的劃分*

? *所有啟動了服務(wù)的進(jìn)程狡汉,且該服務(wù)所在的進(jìn)程沒有顯示過UI闽颇,且該服務(wù)未執(zhí)行startForeground(執(zhí)行后會變?yōu)閜erveptible服務(wù))動作兵多,那該進(jìn)程則為A-Service與B-Service中的一種。然后根據(jù)這類服務(wù)進(jìn)程所處于Lru進(jìn)程表中的位置援雇,前1/3點(diǎn)服務(wù)為A-Service,其余的則為B-Service铣猩。*

*4.perceptible的標(biāo)準(zhǔn)*

? *perceptible名為可感知的進(jìn)程天吓,但并不是說能夠感知到進(jìn)程就一定表示該進(jìn)程屬于perveptible進(jìn)程,比如播放音樂的進(jìn)程活著狀態(tài)欄上有通知的進(jìn)程,雖然能夠感知到進(jìn)程的存在滔金,但是不代表進(jìn)程一定時perceptible類別的進(jìn)程。決定該進(jìn)程是否屬于perceptible進(jìn)程并未進(jìn)程的可感知性忿族,而是該進(jìn)程的服務(wù)是否執(zhí)行了startForeground動作。*

*二、如何查詢應(yīng)用的adj級別*

*1.dumpsys meminfo*

? *使用dumpsys meminfo命令時噪伊,會列出當(dāng)前系統(tǒng)的所有進(jìn)程,不同進(jìn)程放入不同的分類,對應(yīng)的分類名基本與lmk的分類一致良蒸。有一點(diǎn)不同的就是,退到后臺啟動了服務(wù)且顯示過UI的進(jìn)程丽旅,在dumpsys meminfo命令中會歸為b service一類榄笙,但從lmk角度分配的oom_adj值為9~16的范圍,屬于cached一類*

*2.cat /proc/[PID]/oom_adj: 使用該命令會直接顯示出對應(yīng)進(jìn)程號的adj值*

*三、未控制好oom_adj的案例*

*1.ui進(jìn)程啟動service的隱患*

*案例a:備份進(jìn)程啟動一個服務(wù)開始執(zhí)行備份蠕蚜,備份服務(wù)運(yùn)行在ui進(jìn)程(服務(wù)未調(diào)用startForeground())*

*隱患:備份服務(wù)一般需要較長時間,在用戶按Home鍵退出后臺后,備份進(jìn)程會處于previous狀態(tài)睛挚,繼續(xù)使用手機(jī)其他應(yīng)用,會是使得備份進(jìn)程處于cch-started-ui-services的狀態(tài)淤击,即是啟動了服務(wù)并且包含ui的進(jìn)程退到后臺狀態(tài),此時進(jìn)程的adj值處于9~16矢腻,隨著時間推移逐漸增大。如果在較長的備份過程中顷蟆,觸發(fā)了lowmemorykiller逐纬,很容易導(dǎo)致備份進(jìn)程被殺掉,從而導(dǎo)致備份的失敗甸箱。*

*案例b:****備份進(jìn)程啟動一個服務(wù)開始執(zhí)行備份,備份服務(wù)運(yùn)行在ui進(jìn)程(服務(wù)調(diào)用了startForeground())*****

****隱患:這種情況下備份進(jìn)程會被劃分為perceptible進(jìn)程,基本上是不會被lowmemorykiller殺掉的窃躲,但是這也導(dǎo)致內(nèi)存占用較大的備份常駐了,從內(nèi)存管理角度來將,備份進(jìn)程的UI部分是并不期望他常駐的挣输,而大量內(nèi)存的常駐也容易導(dǎo)致lowmemorykiller的出現(xiàn),從而導(dǎo)致系統(tǒng)進(jìn)入內(nèi)存較低的等級,而當(dāng)系統(tǒng)處于內(nèi)存較低等級時拇舀,會觸發(fā)系統(tǒng)回調(diào)所有進(jìn)程進(jìn)行進(jìn)程回收動作薄辅,容易導(dǎo)致系統(tǒng)卡頓場景的出現(xiàn)。此外窿春,********調(diào)用了startForeground()會導(dǎo)致進(jìn)程被系統(tǒng)判定為前景進(jìn)程旧乞,這樣備份進(jìn)程便會搶占用戶操作手機(jī)時前臺應(yīng)用的cpu資源,增加了卡頓場景出現(xiàn)的幾率。**************

*解決方法:將Service運(yùn)行在獨(dú)立的進(jìn)程皮胡,這樣應(yīng)用退到后臺后屡贺,備份服務(wù)進(jìn)程會處于A-Service中(逐漸掉落到B-Service),而B-Service進(jìn)程一般也是很難被lowmemorykiller砍。該獨(dú)立********是否要startForeground()?如果期望保證備份盡快到完成突想,便可以犧牲一些用戶在操作其他應(yīng)用時到用戶體驗(yàn),將服務(wù)推為前景應(yīng)用稽荧;對于很多需要保證功能的流暢運(yùn)行的服務(wù)進(jìn)程姨丈,例如音樂播放髓介,錄音等,則需要將這類服務(wù)進(jìn)程通過********startForeground()設(shè)置為前景進(jìn)程,但前提還是需要做到ui與Service分離洒沦。*********

*2.使用線程解決耗時操作造成anr問題的隱患*

*案例:短信、郵件括尸、或筆記本應(yīng)用,在用戶按BACK鍵時存下草稿*

?

public` `class` `MyActivity extents Activity {``  ` `public` `void` `onPause(){``    ` `//存儲草稿``  ` `}``}

*問題(1):由于存儲草稿定操作一般時保存到數(shù)據(jù)庫,某些情況下可能會占用較長時間雀摘,這里就有可能導(dǎo)致anr的隱患*

*解決方案1:*

?

public` `class` `MyActivity extents Activity {``  ` `public` `void` `onPause(){``    ` `new` `Thread() {``      ` `public` `void` `run() {``        ` `//存儲草稿``      ` `}``    ` `}.start()``  ` `}``}

*問題(2):當(dāng)用戶以back鍵離開應(yīng)用時(以home鍵離開會處于previous狀態(tài)),應(yīng)用退到后臺處于empty-cached狀態(tài),內(nèi)存不足時轧铁,可能會立刻殺齿风。*

*解決方案2:如果線程有這問題童本,是否可以用服務(wù)來完成存儲草稿的動作呢?*

*問題(3):如果用服務(wù)來存儲草稿泵额,即將存儲草稿動作寫在onStartCommand中,由于onStartCommmand操作依舊是執(zhí)行在主線程的羞秤,所以在其中執(zhí)行耗時操作時,依舊可能會導(dǎo)致ANR*

*最終解決方案:使用IntentService來執(zhí)行保存草稿的動作*

?

public` `class` `MyActivity extents Activity {``  ` `public` `void` `onPause(){``    ` `... ``    ` `startService(` `new` `Intent(` `this` `, MyIntentService.` `class` `));``    ` `...``  ` `}``}` `public` `class` `MyIntentService ``extends` `IntentService {``  ` `protected` `void` `onHandleIntent(Intent intent) {``    ` `//保存草稿``  ` `}``}

*3.provider被binder導(dǎo)致的隱患*

*案例:systemui進(jìn)程獲取手機(jī)中的手機(jī)管家應(yīng)用提供的content provider,用于獲取當(dāng)前應(yīng)用相關(guān)信息*

*問題:管家應(yīng)用的UID為System,在Android機(jī)制中咬扇,System UID進(jìn)程提供的provider一旦被訪問经窖,即使訪問完成關(guān)掉provider后,連接依舊存在配乱,所有管家應(yīng)用由于其provider持續(xù)被persistent進(jìn)程咬住桑寨,所以管家應(yīng)用便會長時間處于foreground級別的應(yīng)用中,oom_adj為0沙咏,導(dǎo)致管家應(yīng)用占用的大量內(nèi)存很難被回收*

*解決方案:單獨(dú)使用一個進(jìn)程提供provider,提供provider進(jìn)程由于占用內(nèi)存較小孽尽,所以即使無法被回收也影響較小瞻讽,這樣管家應(yīng)用的UI進(jìn)程能夠按照系統(tǒng)正常的回收流程在需要時被回收*

*四、總結(jié)一些經(jīng)驗(yàn)*

*1.進(jìn)程在啟動服務(wù)后烦磁,在事情做完后,必須呼叫stopService或stopSelf通知框架陨晶,避免事情做完了,服務(wù)進(jìn)程依舊常駐內(nèi)存*

*2.對于需要長時間停留在后臺的服務(wù)褐耳,且服務(wù)設(shè)置為具有重啟特性時买雾,需要做到ui與service分離嗤军,一避免占用內(nèi)存較大的ui進(jìn)程的常駐*

*3.對于需要長時間停留在后臺的服務(wù)老客,且服務(wù)設(shè)置為具有重啟特性時,不可長時間bind住其他進(jìn)程的service或provider尉间,避免其他進(jìn)程常駐;*

*4.常駐性質(zhì)的進(jìn)程(oom_adj<=6)眠副,不可一直bind住其他進(jìn)程的服務(wù)或provider,用完必須馬上放掉*

*5.不可使用SystemUID進(jìn)程內(nèi)的provider娃弓,在Android設(shè)計中,若針對System UID的進(jìn)程使用provider,即使已關(guān)掉provider炼吴,但框架仍會保持provider connection*

*6.利用onStartCommand方法回傳值(START_STICKY,START_NOT_STICKY等)控制好服務(wù)的重啟屬性童芹,在設(shè)計時充分考慮進(jìn)程被lmk殺死的情況*

*7.IntentService繼承自Service,針對CPU scheduling宁否、工作排程等都有完整實(shí)現(xiàn)慕匠,建議多采用IntentnService進(jìn)行功能實(shí)現(xiàn)*

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末青伤,一起剝皮案震驚了整個濱河市狠角,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖晓勇,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異描融,居然都是意外死亡骏庸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辈挂,你說我怎么就攤上這事∧雌” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我谚中,道長,這世上最難降的妖魔是什么蝌麸? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任敢辩,我火速辦了婚禮戚长,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己蟆湖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般棺克。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纱皆,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天派草,我揣著相機(jī)與錄音近迁,去河邊找鬼簸州。 笑死,一個胖子當(dāng)著我的面吹牛瑰步,可吹牛的內(nèi)容都是我干的璧眠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼袁滥,長吁一口氣:“原來是場噩夢啊……” “哼呻拌!你這毒婦竟也來了睦焕?” 一聲冷哼從身側(cè)響起垃喊,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤本谜,失蹤者是張志新(化名)和其女友劉穎乌助,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧掩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年呜袁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祭玉。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡臼疫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤慢逾,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響葛躏,放射性物質(zhì)發(fā)生泄漏败富。R本人自食惡果不足惜兽叮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淘太。 院中可真熱鬧蒲牧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歧寺。三九已至,卻和暖如春顷链,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背革答。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工眠菇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留登疗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓劫拗,卻偏偏與公主長得像四瘫,于是被迫代替她去往敵國和親洗做。 傳聞我的和親對象是個殘疾皇子抬闯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容