Android多進程介紹

在Android中述呐,默認情況下吗坚,同一應用的所有組件均運行在同一進程中菇晃,且大多數(shù)應用都不會改變這一點册倒。不過,單進程開發(fā)并不是Android應用的全部磺送,今天我們就來說說Android中的多進程開發(fā)以及多進程的使用場景剩失。

學習Android的同學注意了!2嶙拧拴孤!

學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Android學習交流群甲捏,群號碼:364595326? 我們一起學Android演熟!

多進程介紹

本篇文章內(nèi)容基于Android Developer官網(wǎng)

進程

我們都知道Android系統(tǒng)是基于Linux改造而來的,進程系統(tǒng)也是一脈相承司顿,進程芒粹,其實就是程序的具體實現(xiàn)。當程序第一次啟動大溜,Android會啟動一個Linux進程(具體由Zygote fork出來)以及一個主線程化漆,默認的情況下,所有組件都將運行在該進程內(nèi)钦奋。同一個應用由系統(tǒng)分配一個獨立的Linux賬戶座云,該應用的產(chǎn)生的所有進程疙赠,都會是這同一個Linux賬戶。

使用多進程

在開發(fā)中朦拖,我們通常會使用修改清單文件的android:process來達到多進程的目的圃阳。activity、service璧帝、receiver和provider均支持android:process屬性捍岳,此屬性可以指定該組件應在哪個進程運行。如果android:process的value值以冒號開頭的話睬隶,那么該進程就是私有進程锣夹,如果是以其他字符開頭,那么就是公有進程苏潜,擁有相同ShareUID的不同應用可以跑在同一進程里晕城,后續(xù)我會專門針對公私有進程做個試驗。另外窖贤,我們還可以通過設置application的android:process屬性砖顷,來設置所有組件的默認進程。

至于創(chuàng)建進程的具體源碼分析赃梧,網(wǎng)上有一篇很詳細的文章滤蝠,在這就不重復造輪子了,有需要的朋友可以前往理解Android進程創(chuàng)建流程

還有一種方法開啟進程授嘀,是通過JNI物咳,利用C/C++,調(diào)用fork()方法來生成子進程蹄皱,一般開發(fā)者會利用這種方法來做一些daemon進程览闰,來實現(xiàn)防殺,毕镎郏活等效果压鉴,不過不是太推薦,這么做锻拘,畢竟Android生態(tài)系統(tǒng)需要大家維護油吭。

進程生命周期

剛剛聊了一下進程的“生”,作為一個生命周期署拟,是時候該聊聊進程的“死”了婉宰。這里再次呼吁一下大家能正視進程的“死”,合理的利用多進程推穷,適當?shù)臍⑺啦槐匾倪M程才是本篇文章所關注的焦點心包,我們不要把“永生”作為自己的實現(xiàn)目標,Android設備內(nèi)存就那么大馒铃,就像地球一樣蟹腾,大家都永生了痕惋,生態(tài)系統(tǒng)就會破壞。那么Android系統(tǒng)是如何維護這個生態(tài)系統(tǒng)的呢岭佳?

其實也是類似于現(xiàn)實生活中的優(yōu)勝略汰,Android利用重要性層次結(jié)構萧锉,就是將最重要的保留珊随,殺掉不重要的進程。Android將重要性層次結(jié)構分為5個層級柿隙,分為了:(以下5級描述節(jié)選自Android進程生命周期

前臺進程

用戶當前操作所必需的進程叶洞。如果一個進程滿足以下任一條件,即視為前臺進程:

托管用戶正在交互的Activity(已調(diào)用Activity的onResume()方法)

托管某個Service禀崖,后者綁定到用戶正在交互的Activity

托管正在“前臺”運行的Service(服務已調(diào)用startForeground())

托管正執(zhí)行一個生命周期回調(diào)的Service(onCreate()衩辟、onStart()或onDestroy())

托管正執(zhí)行其onReceive()方法的BroadcastReceiver

通常,在任意給定時間前臺進程都為數(shù)不多波附。只有在內(nèi)存不足以支持它們同時繼續(xù)運行這一萬不得已的情況下艺晴,系統(tǒng)才會終止它們。 此時掸屡,設備往往已達到內(nèi)存分頁狀態(tài)封寞,因此需要終止一些前臺進程來確保用戶界面正常響應。

這就需要依靠系統(tǒng)的資源仅财。

可見進程

沒有任何前臺組件狈究、但仍會影響用戶在屏幕上所見內(nèi)容的進程。 如果一個進程滿足以下任一條件盏求,即視為可見進程:

托管不在前臺抖锥、但仍對用戶可見的Activity(已調(diào)用其onPause()方法)。例如碎罚,如果前臺Activity啟動了一個對話框磅废,允許在其后顯示上一Activity,則有可能會發(fā)生這種情況荆烈。

托管綁定到可見(或前臺)Activity的Service还蹲。

可見進程被視為是極其重要的進程,除非為了維持所有前臺進程同時運行而必須終止耙考,否則系統(tǒng)不會終止這些進程谜喊。

服務進程

正在運行已使用startService()方法啟動的服務且不屬于上述兩個更高類別進程的進程。盡管服務進程與用戶所見內(nèi)容沒有直接關聯(lián)倦始,但是它們通常在執(zhí)行一些用戶關心的操作(例如斗遏,在后臺播放音樂或從網(wǎng)絡下載數(shù)據(jù))。因此鞋邑,除非內(nèi)存不足以維持所有前臺進程和可見進程同時運行诵次,否則系統(tǒng)會讓服務進程保持運行狀態(tài)账蓉。

后臺進程

包含目前對用戶不可見的Activity的進程(已調(diào)用Activity的onStop()方法)。這些進程對用戶體驗沒有直接影響逾一,系統(tǒng)可能隨時終止它們铸本,以回收內(nèi)存供前臺進程、可見進程或服務進程使用遵堵。 通常會有很多后臺進程在運行箱玷,因此它們會保存在 LRU (最近最少使用)列表中,以確保包含用戶最近查看的Activity的進程最后一個被終止陌宿。如果某個Activity正確實現(xiàn)了生命周期方法锡足,并保存了其當前狀態(tài),則終止其進程不會對用戶體驗產(chǎn)生明顯影響壳坪,因為當用戶導航回該Activity時舶得,Activity會恢復其所有可見狀態(tài)。 有關保存和恢復狀態(tài)的信息爽蝴,請參閱Activity文檔沐批。

空進程

不含任何活動應用組件的進程。保留這種進程的的唯一目的是用作緩存蝎亚,以縮短下次在其中運行組件所需的啟動時間珠插。 為使總體系統(tǒng)資源在進程緩存和底層內(nèi)核緩存之間保持平衡,系統(tǒng)往往會終止這些進程颖对。

根據(jù)進程中當前活動組件的重要程度捻撑,Android 會將進程評定為它可能達到的最高級別。例如缤底,如果某進程托管著服務和可見Activity顾患,則會將此進程評定為可見進程,而不是服務進程个唧。

此外江解,一個進程的級別可能會因其他進程對它的依賴而有所提高,即服務于另一進程的進程其級別永遠不會低于其所服務的進程徙歼。 例如犁河,如果進程 A 中的內(nèi)容提供程序為進程 B 中的客戶端提供服務,或者如果進程 A 中的服務綁定到進程 B 中的組件魄梯,則進程 A 始終被視為至少與進程 B 同樣重要桨螺。

由于運行服務的進程其級別高于托管后臺Activity的進程,因此啟動長時間運行操作的Activity最好為該操作啟動服務酿秸,而不是簡單地創(chuàng)建工作線程灭翔,當操作有可能比Activity更加持久時尤要如此。例如辣苏,正在將圖片上傳到網(wǎng)站的Activity應該啟動服務來執(zhí)行上傳肝箱,這樣一來哄褒,即使用戶退出Activity,仍可在后臺繼續(xù)執(zhí)行上傳操作煌张。使用服務可以保證呐赡,無論Activity發(fā)生什么情況,該操作至少具備“服務進程”優(yōu)先級骏融。 同理链嘀,廣播接收器也應使用服務,而不是簡單地將耗時冗長的操作放入線程中绎谦。

Low Memory Killer

進程按照狀態(tài)分完重要性之后管闷,就要開始殺進程了粥脚。Android的Low Memory Killer基于Linux的OOM機制窃肠,在Linux中,內(nèi)存是以頁面(page)為單位刷允,當申請頁面分配不足的時候冤留,系統(tǒng)會通過Low Memory Killer來殺掉bad進程,釋放內(nèi)存树灶。Low Memory Killer會根據(jù)進程的adj級別以及所占的內(nèi)存纤怒,來決定是否殺掉該進程,adj越大天通,占用內(nèi)存越多泊窘,進程越容易被殺掉。

關于adj的分級像寒,我們可以參考ProcessList.java烘豹,這里面的常量定義了ADJ的分級。(7.0以后的adj分級與之前的不太一樣(Processlist.java-Nougat)诺祸,這個我們后續(xù)可以研究一下具體的改動是什么)

adj分級:

UNKNOWN_ADJ = 16

級別最低級的進程携悯,通常是被緩存的進程,但是系統(tǒng)也不清楚緩存的內(nèi)容筷笨。

CACHED_APP_MAX_ADJ = 15

這是一個只托管不可見的活動的進程憔鬼,因此可以在沒有任何中斷的情況下被殺死。

CACHED_APP_MIN_ADJ = 9

緩存進程胃夏,沒有英文解釋轴或。

SERVICE_B_ADJ = 8

不活躍的服務,不想adj=5的服務那么活躍仰禀。

PS:這里說一句侮叮,在root以后,有的系統(tǒng)優(yōu)化大師悼瘾,會把所有服務統(tǒng)一調(diào)成adj=8這個級別囊榜,來達到內(nèi)存優(yōu)化的目的审胸,后面我們會說到。

PREVIOUS_APP_ADJ = 7

被切換的進程卸勺,一般是用戶前一個使用的進程砂沛。兩個應用來回切換,那么前一個應用一般adj設置為7曙求。

HOME_APP_ADJ = 6

與主應用程序有交互的進程碍庵。

SERVICE_ADJ = 5

活躍的服務進程。

HEAVY_WEIGHT_APP_ADJ = 4

高權重進程

BACKUP_APP_ADJ = 3

正在備份的進程

PERCEPTIBLE_APP_ADJ = 2

可感知進程(通常是前臺Service進程)

VISIBLE_APP_ADJ = 1

可見進程

FOREGROUND_APP_ADJ = 0

前臺進程

剩下的就是adj值為負數(shù)的進程悟狱,基本上都是系統(tǒng)集成静浴,不在本文的討論范圍內(nèi)。負數(shù)進程是不會被lmk殺掉的挤渐。

如何查看進程優(yōu)先級

首先通過 adb shell ps 指令查找對應進程的pid

然后通過 adb shell cat /proc/${pid}/oom_adj(設備需要root)返回對應進程的adj值苹享。

還可以把oom_adj替換成oom_score或者oom_score_adj來查看這兩項的數(shù)值,當oom_adj相同時浴麻,LowMemoryKiller會根據(jù)oom_score_adj和RSS內(nèi)存大小來殺掉對應的進程得问。

查看設備的內(nèi)存臨界值

我們可以通過adb shell cat 查看下面兩個文件

/sys/module/lowmemorykiller/parameters/adj

/sys/module/lowmemorykiller/parameters/minfree

(這里請注意,這兩個文件是只可以寫入的软免,cat之前請先用chmod賦予權限宫纬。)

adj 代表的是oom_score_adj的值,對應的minfree則代表內(nèi)存臨界值膏萧。

比如我的測試機小米4C測試機對應的值就是:

adj: 0,58,117,176,529,1000

這個值其實是oom_score_adj的值漓骚,用這個值*17再除1000四舍五入取整數(shù),就是對應的adj的值榛泛,例如第二個值58即為 58*17/1000 = 1蝌蹂,對應的adj也就是1,所以這6個值對應的adj是0挟鸠,1叉信,2,3艘希,9硼身,15。1000默認就是15

minfree: 18432,23040,27648,32256,56250,81250

這個值是頁值覆享,一頁等于4KB佳遂,換算成MB大概是72,90撒顿,108丑罪,126,220,318

當可用內(nèi)存小于318MB的時候吩屹,系統(tǒng)開始殺adj=15的進程跪另,以此類推。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煤搜,一起剝皮案震驚了整個濱河市免绿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌擦盾,老刑警劉巖嘲驾,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迹卢,居然都是意外死亡辽故,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門腐碱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來誊垢,“玉大人,你說我怎么就攤上這事喻杈⊥啵” “怎么了狰晚?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵筒饰,是天一觀的道長。 經(jīng)常有香客問我壁晒,道長瓷们,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任秒咐,我火速辦了婚禮谬晕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘携取。我一直安慰自己攒钳,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布雷滋。 她就那樣靜靜地躺著不撑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晤斩。 梳的紋絲不亂的頭發(fā)上焕檬,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音澳泵,去河邊找鬼实愚。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的腊敲。 我是一名探鬼主播击喂,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碰辅!你這毒婦竟也來了茫负?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤乎赴,失蹤者是張志新(化名)和其女友劉穎忍法,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榕吼,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡饿序,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了羹蚣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片原探。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖顽素,靈堂內(nèi)的尸體忽然破棺而出咽弦,到底是詐尸還是另有隱情,我是刑警寧澤胁出,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布型型,位于F島的核電站,受9級特大地震影響全蝶,放射性物質(zhì)發(fā)生泄漏闹蒜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一抑淫、第九天 我趴在偏房一處隱蔽的房頂上張望绷落。 院中可真熱鬧,春花似錦始苇、人聲如沸砌烁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽函喉。三九已至,卻和暖如春蓄氧,著一層夾襖步出監(jiān)牢的瞬間函似,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工喉童, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撇寞,地道東北人顿天。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像蔑担,于是被迫代替她去往敵國和親牌废。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評論 25 707
  • 本篇文章是后臺殺死系列的最后一篇蹲蒲,主要探討一下進程的狈Γ活,Android本身設計的時候是非常善良的届搁,它希望進程在不...
    看書的小蝸牛閱讀 11,663評論 10 66
  • 什么情況需要使用多線程 常駐后臺任務應用 類似音樂類缘薛、跑步健身類、手機管家類等長時間需要在后臺運行的應用卡睦。這些應用...
    TensorFlow開發(fā)者閱讀 1,805評論 0 3
  • C讀經(jīng): - 詩篇31:4 求你救我脫離人為我暗設的網(wǎng)羅.因為你是我的保障宴胧。 現(xiàn)在的人越來越聰明,也更加狡猾表锻。在社...
    NCNeverland閱讀 140評論 0 0
  • 我不知道挺過了這段苦澀的戀期恕齐,我們最終會變成什么樣子,至少現(xiàn)在我腦袋里面對未來的幻想逐漸變得蒼白無力浩嫌,我們還可以繼...
    小樹97閱讀 148評論 0 0