Android進(jìn)程生命周期與ADJ

一纽什、 進(jìn)程生命周期

Android系統(tǒng)將盡量長(zhǎng)時(shí)間地保持應(yīng)用進(jìn)程纪岁,但為了新建進(jìn)程或運(yùn)行更重要的進(jìn)程卒密,最終需要清除舊進(jìn)程來(lái)回收內(nèi)存。 為了確定保留或終止哪些進(jìn)程岳掐,系統(tǒng)會(huì)根據(jù)進(jìn)程中正在運(yùn)行的組件以及這些組件的狀態(tài)凭疮,將每個(gè)進(jìn)程放入“重要性層次結(jié)構(gòu)”中。 必要時(shí)串述,系統(tǒng)會(huì)首先消除重要性最低的進(jìn)程执解,然后是清除重要性稍低一級(jí)的進(jìn)程,依此類推纲酗,以回收系統(tǒng)資源衰腌。

進(jìn)程的重要性,劃分5級(jí):

前臺(tái)進(jìn)程(Foreground process)
可見(jiàn)進(jìn)程(Visible process)
服務(wù)進(jìn)程(Service process)
后臺(tái)進(jìn)程(Background process)
空進(jìn)程(Empty process)
前臺(tái)進(jìn)程的重要性最高觅赊,依次遞減右蕊,空進(jìn)程的重要性最低,下面分別來(lái)闡述每種級(jí)別的進(jìn)程

1.1 Foreground process

用戶當(dāng)前操作所必需的進(jìn)程吮螺。通常在任意給定時(shí)間前臺(tái)進(jìn)程都為數(shù)不多饶囚。只有在內(nèi)存不足以支持它們同時(shí)繼續(xù)運(yùn)行這一萬(wàn)不得已的情況下,系統(tǒng)才會(huì)終止它們鸠补。

  • 擁有用戶正在交互的 Activity(已調(diào)用onResume())
  • 擁有某個(gè) Service萝风,后者綁定到用戶正在交互的 Activity
  • 擁有正在“前臺(tái)”運(yùn)行的 Service(服務(wù)已調(diào)用 startForeground())
  • 擁有正執(zhí)行一個(gè)生命周期回調(diào)的 Service(onCreate()、onStart() 或 onDestroy())
  • 擁有正執(zhí)行其 onReceive() 方法的 BroadcastReceiver

1.2 Visible process

沒(méi)有任何前臺(tái)組件莫鸭、但仍會(huì)影響用戶在屏幕上所見(jiàn)內(nèi)容的進(jìn)程闹丐。可見(jiàn)進(jìn)程被視為是極其重要的進(jìn)程被因,除非為了維持所有前臺(tái)進(jìn)程同時(shí)運(yùn)行而必須終止卿拴,否則系統(tǒng)不會(huì)終止這些進(jìn)程。

  • 擁有不在前臺(tái)梨与、但仍對(duì)用戶可見(jiàn)的 Activity(已調(diào)用onPause())堕花。
  • 擁有綁定到可見(jiàn)(或前臺(tái))Activity 的 Service

1.3 Service process

盡管服務(wù)進(jìn)程與用戶所見(jiàn)內(nèi)容沒(méi)有直接關(guān)聯(lián),但是它們通常在執(zhí)行一些用戶關(guān)心的操作(例如粥鞋,在后臺(tái)播放音樂(lè)或從網(wǎng)絡(luò)下載數(shù)據(jù))缘挽。因此,除非內(nèi)存不足以維持所有前臺(tái)進(jìn)程和可見(jiàn)進(jìn)程同時(shí)運(yùn)行,否則系統(tǒng)會(huì)讓服務(wù)進(jìn)程保持運(yùn)行狀態(tài)壕曼。

  • 正在運(yùn)行startService()方法啟動(dòng)的服務(wù)苏研,且不屬于上述兩個(gè)更高類別進(jìn)程的進(jìn)程。

1.4 Background process

后臺(tái)進(jìn)程對(duì)用戶體驗(yàn)沒(méi)有直接影響腮郊,系統(tǒng)可能隨時(shí)終止它們摹蘑,以回收內(nèi)存供前臺(tái)進(jìn)程、可見(jiàn)進(jìn)程或服務(wù)進(jìn)程使用轧飞。 通常會(huì)有很多后臺(tái)進(jìn)程在運(yùn)行衅鹿,因此它們會(huì)保存在LRU列表中,以確保包含用戶最近查看的Activity的進(jìn)程最后一個(gè)被終止过咬。如果某個(gè) Activity 正確實(shí)現(xiàn)了生命周期方法大渤,并保存了其當(dāng)前狀態(tài),則終止其進(jìn)程不會(huì)對(duì)用戶體驗(yàn)產(chǎn)生明顯影響掸绞,因?yàn)楫?dāng)用戶導(dǎo)航回該 Activity 時(shí)泵三,Activity 會(huì)恢復(fù)其所有可見(jiàn)狀態(tài)。

  • 對(duì)用戶不可見(jiàn)的Activity的進(jìn)程(已調(diào)用Activity的onStop()方法)

1.5 Empty process

保留這種進(jìn)程的的唯一目的是用作緩存衔掸,以縮短下次在其中運(yùn)行組件所需的啟動(dòng)時(shí)間切黔。 為使總體系統(tǒng)資源在進(jìn)程緩存和底層內(nèi)核緩存之間保持平衡,系統(tǒng)往往會(huì)終止這些進(jìn)程具篇。

  • 不含任何活動(dòng)應(yīng)用組件的進(jìn)程

二、Lowmemorykiller

2.1 ADJ級(jí)別

定義在ProcessList.java文件凌埂,oom_adj劃分為16級(jí)驱显,從-1000到1001之間取值。

ADJ級(jí)別 取值 解釋
UNKNOWN_ADJ 1001 一般指將要會(huì)緩存進(jìn)程瞳抓,無(wú)法獲取確定值
CACHED_APP_MAX_ADJ 999 不可見(jiàn)進(jìn)程的adj最大值
CACHED_APP_MIN_ADJ 900 不可見(jiàn)進(jìn)程的adj最小值
SERVICE_B_AD 800 B List中的Service(較老的埃疫、使用可能性更小)
PREVIOUS_APP_ADJ 700 上一個(gè)App的進(jìn)程(往往通過(guò)按返回鍵)
HOME_APP_ADJ 600 Home進(jìn)程
SERVICE_ADJ 500 服務(wù)進(jìn)程(Service process)
HEAVY_WEIGHT_APP_ADJ 400 后臺(tái)的重量級(jí)進(jìn)程孩哑,system/rootdir/init.rc文件中設(shè)置
BACKUP_APP_ADJ 300 備份進(jìn)程
PERCEPTIBLE_APP_ADJ 200 可感知進(jìn)程栓霜,比如后臺(tái)音樂(lè)播放
VISIBLE_APP_ADJ 100 可見(jiàn)進(jìn)程(Visible process)
FOREGROUND_APP_ADJ 50 前臺(tái)進(jìn)程(Foreground process)
PERSISTENT_SERVICE_ADJ -700 關(guān)聯(lián)著系統(tǒng)或persistent進(jìn)程
PERSISTENT_PROC_ADJ -800 系統(tǒng)persistent進(jìn)程,比如telephony
SYSTEM_ADJ -900 系統(tǒng)進(jìn)程
NATIVE_ADJ -1000 native進(jìn)程(不被系統(tǒng)管理)

這里按照Android對(duì)進(jìn)程的分類横蜒,粗略劃分一下不同oom_adj對(duì)應(yīng)的場(chǎng)景

image.png
14.png

2.2 進(jìn)程state級(jí)別

定義在ActivityManager.java文件胳蛮,process_state,從-1到20之間取值丛晌。

state級(jí)別 取值 解釋
PROCESS_STATE_NONEXISTENT 20 進(jìn)程不存在
PROCESS_STATE_CACHED_EMPTY 19 進(jìn)程處于cached狀態(tài)仅炊,且為空進(jìn)程
PROCESS_STATE_CACHED_RECENT 18 與recent中關(guān)聯(lián)的緩存進(jìn)程
PROCESS_STATE_CACHED_ACTIVITY_CLIENT 17 托管存在客戶端的Activity的進(jìn)程
PROCESS_STATE_CACHED_ACTIVITY 16 后臺(tái)托管有Activity的進(jìn)程
PROCESS_STATE_LAST_ACTIVITY 15 后臺(tái)進(jìn)程,但是托管了用戶最后運(yùn)行的Activity
PROCESS_STATE_HOME 14 Home進(jìn)程
PROCESS_STATE_HEAVY_WEIGHT 13 重量級(jí)進(jìn)程
PROCESS_STATE_TOP_SLEEPING 12 和PROCESS_STATE_TOP一樣澎蛛,但是區(qū)別是手機(jī)處于sleeping狀態(tài)
PROCESS_STATE_RECEIVER 11 后臺(tái)進(jìn)程抚垄,且正在運(yùn)行receiver
PROCESS_STATE_SERVICE 10 后臺(tái)進(jìn)程,且正在運(yùn)行service
PROCESS_STATE_BACKUP 9 備份進(jìn)程
PROCESS_STATE_TRANSTENT_BACKGROUND 8 對(duì)于用戶比較重要的后臺(tái)進(jìn)程
PROCESS_STATE_IMPORTANT_BACKGROUND 7 對(duì)用戶很重要的進(jìn)程,用戶可感知其存在
PROCESS_STATE_IMPORTANT_FOREGROUND 6 對(duì)于用戶比較重要的前臺(tái)進(jìn)程
PROCESS_STATE_BOUND_FOREGROUND_SERVICE 5 通過(guò)bind的形式托管前臺(tái)服務(wù)的進(jìn)程
PROCESS_STATE_FOREGROUND_SERVICE 4 托管前臺(tái)服務(wù)的進(jìn)程
PROCESS_STATE_BOUND_TOP 3 進(jìn)程綁定到一個(gè)TOP應(yīng)用呆馁。它的排名低于SERVICE_LOCATION
PROCESS_STATE_TOP 2 涵蓋了用戶可見(jiàn)活動(dòng)的進(jìn)程
PROCESS_STATE_PERSISTENT_UI 1 系統(tǒng)persistent進(jìn)程桐经,正在進(jìn)行UI相關(guān)的操作
PROCESS_STATE_PERSISTENT 0 系統(tǒng)persistent進(jìn)程
PROCESS_STATE_UNKNOWN -1 不存在的進(jìn)程

2.3 lmk策略

Lowmemorykiller根據(jù)當(dāng)前可用內(nèi)存情況來(lái)進(jìn)行進(jìn)程釋放,總設(shè)計(jì)了6個(gè)級(jí)別浙滤,即Lowmemorykiller的殺進(jìn)程的6檔阴挣,如下:

  1. CACHED_APP_MAX_ADJ
  2. CACHED_APP_MIN_ADJ
  3. BACKUP_APP_ADJ
  4. PERCEPTIBLE_APP_ADJ
  5. VISIBLE_APP_ADJ
  6. FOREGROUND_APP_ADJ

系統(tǒng)內(nèi)存從很寬裕到不足,Lowmemorykiller也會(huì)相應(yīng)地從CACHED_APP_MAX_ADJ(第1檔)開(kāi)始?xì)⑦M(jìn)程瓷叫,如果內(nèi)存還不足屯吊,那么會(huì)殺CACHED_APP_MIN_ADJ(第2檔),不斷深入摹菠,直到滿足內(nèi)存閾值條件盒卸。

三、 進(jìn)程調(diào)度adj算法

ADJ算法的核心方法:

  • updateOomAdjLocked:更新adj次氨,當(dāng)目標(biāo)進(jìn)程為空蔽介,或者被殺則返回false;否則返回true;
  • computeOomAdjLocked:計(jì)算adj煮寡,返回計(jì)算后RawAdj值;
  • applyOomAdjLocked:應(yīng)用adj虹蓄,當(dāng)需要?dú)⒌裟繕?biāo)進(jìn)程則返回false;否則返回true幸撕。

調(diào)整adj的3的方法薇组,最為常見(jiàn)的方法便是updateOomAdjLocked,這也是其他各個(gè)方法在需要更新adj時(shí)會(huì)調(diào)用的方法坐儿。

四律胀、ADJ的更新時(shí)機(jī)

哪些場(chǎng)景下都會(huì)觸發(fā)updateOomAdjLocked來(lái)更新進(jìn)程adj:

4.1 Activity

  • ASS.realStartActivityLocked: 啟動(dòng)Activity
  • AS.resumeTopActivityInnerLocked: 恢復(fù)棧頂Activity
  • AS.finishCurrentActivityLocked: 結(jié)束當(dāng)前Activity
  • AS.destroyActivityLocked: 摧毀當(dāng)前Activity

4.2 Service

位于ActiveServices.java

  • realStartServiceLocked: 啟動(dòng)服務(wù)
  • bindServiceLocked: 綁定服務(wù)(只更新當(dāng)前app)
  • unbindServiceLocked: 解綁服務(wù) (只更新當(dāng)前app)
  • bringDownServiceLocked: 結(jié)束服務(wù) (只更新當(dāng)前app)
  • sendServiceArgsLocked: 在bringup或則cleanup服務(wù)過(guò)程調(diào)用 (只更新當(dāng)前app)

4.3 broadcast

  • BQ.processNextBroadcast: 處理下一個(gè)廣播
  • BQ.processCurBroadcastLocked: 處理當(dāng)前廣播
  • BQ.deliverToRegisteredReceiverLocked: 分發(fā)已注冊(cè)的廣播 (只更新當(dāng)前app)

4.4 ContentProvider

  • AMS.removeContentProvider: 移除provider
  • AMS.publishContentProviders: 發(fā)布provider (只更新當(dāng)前app)
  • AMS.getContentProviderImpl: 獲取provider (只更新當(dāng)前app)

4.5 Process

位于ActivityManagerService.java

  • setSystemProcess: 創(chuàng)建并設(shè)置系統(tǒng)進(jìn)程
  • addAppLocked: 創(chuàng)建persistent進(jìn)程
  • attachApplicationLocked: 進(jìn)程創(chuàng)建后attach到system_server的過(guò)程;
  • trimApplications: 清除沒(méi)有使用app
  • appDiedLocked: 進(jìn)程死亡
  • killAllBackgroundProcesses: 殺死所有后臺(tái)進(jìn)程.即(ADJ>9或removed=true的普通進(jìn)程)
  • killPackageProcessesLocked: 以包名的形式 殺掉相關(guān)進(jìn)程;

五、updateOomAdjLocked

5.1 重要方法

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
      @GuardedBy("this")
      final void updateOomAdjLocked(String oomAdjReason) {
          mOomAdjuster.updateOomAdjLocked(oomAdjReason);
      }

      /*
       * Update OomAdj for a specific process and its reachable processes.
       * @param app The process to update
       * @param oomAdjReason
       */
      @GuardedBy("this")
      final void updateOomAdjLocked(ProcessRecord app, String oomAdjReason) {
          mOomAdjuster.updateOomAdjLocked(app, oomAdjReason);
      }

/frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
      

       /**
       * Update OomAdj for all processes in LRU list
       */
      @GuardedBy("mService")
      void updateOomAdjLocked(String oomAdjReason) {
//獲取棧頂Activity
          final ProcessRecord topApp = mService.getTopAppLocked();
          updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true);
      }
      /**
       * Update OomAdj for all processes within the given list (could be partial), or the whole LRU
       * list if the given list is null; when it's partial update, each process's client proc won't
       * get evaluated recursively here.
       */
      @GuardedBy("mService")
      private void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp,
              ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,
              boolean startProfiling) {
        private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
              ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
              boolean computeClients) {
       /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
      @GuardedBy("mService")
      private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
              long nowElapsed) {

等重要方法貌矿。

  • updateOomAdjLocked在應(yīng)用進(jìn)程的組件運(yùn)行狀態(tài)發(fā)生改變時(shí)被調(diào)用炭菌,比如有Service啟動(dòng),有廣播接收者收到廣播逛漫,有Activity啟動(dòng)等黑低,這很好理解,因?yàn)檫M(jìn)程重要性的計(jì)算就依賴于組件運(yùn)行狀態(tài)酌毡,既然組件運(yùn)行狀態(tài)發(fā)生了改變克握,就應(yīng)該實(shí)時(shí)更新;
  • computeOomAdjLocked根據(jù)一定規(guī)則計(jì)算出三個(gè)狀態(tài)值枷踏,這個(gè)規(guī)則跟Android將進(jìn)程劃分的5個(gè)優(yōu)先級(jí)有關(guān)系玛荞,即前臺(tái)進(jìn)程、可見(jiàn)進(jìn)程呕寝、服務(wù)進(jìn)程勋眯、后臺(tái)進(jìn)程婴梧、空進(jìn)程,這里不詳細(xì)說(shuō)明客蹋;
  • applyOomAdjLocked將computeOomAdjLocked計(jì)算出的三個(gè)狀態(tài)值應(yīng)用起來(lái)塞蹭,即真正發(fā)揮這三個(gè)狀態(tài)值的作用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末讶坯,一起剝皮案震驚了整個(gè)濱河市番电,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辆琅,老刑警劉巖漱办,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婉烟,死亡現(xiàn)場(chǎng)離奇詭異娩井,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)似袁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門洞辣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人昙衅,你說(shuō)我怎么就攤上這事扬霜。” “怎么了而涉?”我有些...
    開(kāi)封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵著瓶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我啼县,道長(zhǎng)蟹但,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任谭羔,我火速辦了婚禮,結(jié)果婚禮上麦向,老公的妹妹穿的比我還像新娘瘟裸。我一直安慰自己,他們只是感情好诵竭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布话告。 她就那樣靜靜地躺著,像睡著了一般卵慰。 火紅的嫁衣襯著肌膚如雪沙郭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天裳朋,我揣著相機(jī)與錄音病线,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛送挑,可吹牛的內(nèi)容都是我干的绑莺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惕耕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纺裁!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起司澎,我...
    開(kāi)封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤欺缘,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后挤安,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谚殊,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年漱受,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了络凿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昂羡,死狀恐怖絮记,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虐先,我是刑警寧澤怨愤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蛹批,受9級(jí)特大地震影響撰洗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腐芍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一差导、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猪勇,春花似錦设褐、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至椅您,卻和暖如春外冀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掀泳。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工雪隧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留西轩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓膀跌,卻偏偏與公主長(zhǎng)得像遭商,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捅伤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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