Android多進程介紹

在Android中,默認情況下,同一應用的所有組件均運行在同一進程中,且大多數應用都不會改變這一點。不過,單進程開發並不是Android應用的全部,今天我們就來說說Android中的多進程開發以及多進程的使用場景。

學習Android的同學注意了!!!

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

多進程介紹

本篇文章內容基於Android Developer官網

進程

我們都知道Android系統是基於Linux改造而來的,進程系統也是一脈相承,進程,其實就是程序的具體實現。當程序第一次啓動,Android會啓動一個Linux進程(具體由Zygote fork出來)以及一個主線程,默認的情況下,所有組件都將運行在該進程內。同一個應用由系統分配一個獨立的Linux賬戶,該應用的產生的所有進程,都會是這同一個Linux賬戶。

使用多進程

在開發中,我們通常會使用修改清單文件的android:process來達到多進程的目的。activity、service、receiver和provider均支持android:process屬性,此屬性可以指定該組件應在哪個進程運行。如果android:process的value值以冒號開頭的話,那麼該進程就是私有進程,如果是以其他字符開頭,那麼就是公有進程,擁有相同ShareUID的不同應用可以跑在同一進程裏,後續我會專門針對公私有進程做個試驗。另外,我們還可以通過設置application的android:process屬性,來設置所有組件的默認進程。

至於創建進程的具體源碼分析,網上有一篇很詳細的文章,在這就不重複造輪子了,有需要的朋友可以前往理解Android進程創建流程

還有一種方法開啓進程,是通過JNI,利用C/C++,調用fork()方法來生成子進程,一般開發者會利用這種方法來做一些daemon進程,來實現防殺,保活等效果,不過不是太推薦,這麼做,畢竟Android生態系統需要大家維護。

進程生命週期

剛剛聊了一下進程的“生”,作爲一個生命週期,是時候該聊聊進程的“死”了。這裏再次呼籲一下大家能正視進程的“死”,合理的利用多進程,適當的殺死不必要的進程纔是本篇文章所關注的焦點,我們不要把“永生”作爲自己的實現目標,Android設備內存就那麼大,就像地球一樣,大家都永生了,生態系統就會破壞。那麼Android系統是如何維護這個生態系統的呢?

其實也是類似於現實生活中的優勝略汰,Android利用重要性層次結構,就是將最重要的保留,殺掉不重要的進程。Android將重要性層次結構分爲5個層級,分爲了:(以下5級描述節選自Android進程生命週期

前臺進程

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

託管用戶正在交互的Activity(已調用Activity的onResume()方法)

託管某個Service,後者綁定到用戶正在交互的Activity

託管正在“前臺”運行的Service(服務已調用startForeground())

託管正執行一個生命週期回調的Service(onCreate()、onStart()或onDestroy())

託管正執行其onReceive()方法的BroadcastReceiver

通常,在任意給定時間前臺進程都爲數不多。只有在內存不足以支持它們同時繼續運行這一萬不得已的情況下,系統纔會終止它們。 此時,設備往往已達到內存分頁狀態,因此需要終止一些前臺進程來確保用戶界面正常響應。

這就需要依靠系統的資源。

可見進程

沒有任何前臺組件、但仍會影響用戶在屏幕上所見內容的進程。 如果一個進程滿足以下任一條件,即視爲可見進程:

託管不在前臺、但仍對用戶可見的Activity(已調用其onPause()方法)。例如,如果前臺Activity啓動了一個對話框,允許在其後顯示上一Activity,則有可能會發生這種情況。

託管綁定到可見(或前臺)Activity的Service。

可見進程被視爲是極其重要的進程,除非爲了維持所有前臺進程同時運行而必須終止,否則系統不會終止這些進程。

服務進程

正在運行已使用startService()方法啓動的服務且不屬於上述兩個更高類別進程的進程。儘管服務進程與用戶所見內容沒有直接關聯,但是它們通常在執行一些用戶關心的操作(例如,在後臺播放音樂或從網絡下載數據)。因此,除非內存不足以維持所有前臺進程和可見進程同時運行,否則系統會讓服務進程保持運行狀態。

後臺進程

包含目前對用戶不可見的Activity的進程(已調用Activity的onStop()方法)。這些進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供前臺進程、可見進程或服務進程使用。 通常會有很多後臺進程在運行,因此它們會保存在 LRU (最近最少使用)列表中,以確保包含用戶最近查看的Activity的進程最後一個被終止。如果某個Activity正確實現了生命週期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,因爲當用戶導航回該Activity時,Activity會恢復其所有可見狀態。 有關保存和恢復狀態的信息,請參閱Activity文檔。

空進程

不含任何活動應用組件的進程。保留這種進程的的唯一目的是用作緩存,以縮短下次在其中運行組件所需的啓動時間。 爲使總體系統資源在進程緩存和底層內核緩存之間保持平衡,系統往往會終止這些進程。

根據進程中當前活動組件的重要程度,Android 會將進程評定爲它可能達到的最高級別。例如,如果某進程託管着服務和可見Activity,則會將此進程評定爲可見進程,而不是服務進程。

此外,一個進程的級別可能會因其他進程對它的依賴而有所提高,即服務於另一進程的進程其級別永遠不會低於其所服務的進程。 例如,如果進程 A 中的內容提供程序爲進程 B 中的客戶端提供服務,或者如果進程 A 中的服務綁定到進程 B 中的組件,則進程 A 始終被視爲至少與進程 B 同樣重要。

由於運行服務的進程其級別高於託管後臺Activity的進程,因此啓動長時間運行操作的Activity最好爲該操作啓動服務,而不是簡單地創建工作線程,當操作有可能比Activity更加持久時尤要如此。例如,正在將圖片上傳到網站的Activity應該啓動服務來執行上傳,這樣一來,即使用戶退出Activity,仍可在後臺繼續執行上傳操作。使用服務可以保證,無論Activity發生什麼情況,該操作至少具備“服務進程”優先級。 同理,廣播接收器也應使用服務,而不是簡單地將耗時冗長的操作放入線程中。

Low Memory Killer

進程按照狀態分完重要性之後,就要開始殺進程了。Android的Low Memory Killer基於Linux的OOM機制,在Linux中,內存是以頁面(page)爲單位,當申請頁面分配不足的時候,系統會通過Low Memory Killer來殺掉bad進程,釋放內存。Low Memory Killer會根據進程的adj級別以及所佔的內存,來決定是否殺掉該進程,adj越大,佔用內存越多,進程越容易被殺掉。

關於adj的分級,我們可以參考ProcessList.java,這裏面的常量定義了ADJ的分級。(7.0以後的adj分級與之前的不太一樣(Processlist.java-Nougat),這個我們後續可以研究一下具體的改動是什麼)

adj分級:

UNKNOWN_ADJ = 16

級別最低級的進程,通常是被緩存的進程,但是系統也不清楚緩存的內容。

CACHED_APP_MAX_ADJ = 15

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

CACHED_APP_MIN_ADJ = 9

緩存進程,沒有英文解釋。

SERVICE_B_ADJ = 8

不活躍的服務,不想adj=5的服務那麼活躍。

PS:這裏說一句,在root以後,有的系統優化大師,會把所有服務統一調成adj=8這個級別,來達到內存優化的目的,後面我們會說到。

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值爲負數的進程,基本上都是系統集成,不在本文的討論範圍內。負數進程是不會被lmk殺掉的。

如何查看進程優先級

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

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

還可以把oom_adj替換成oom_score或者oom_score_adj來查看這兩項的數值,當oom_adj相同時,LowMemoryKiller會根據oom_score_adj和RSS內存大小來殺掉對應的進程。

查看設備的內存臨界值

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

/sys/module/lowmemorykiller/parameters/adj

/sys/module/lowmemorykiller/parameters/minfree

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

adj 代表的是oom_score_adj的值,對應的minfree則代表內存臨界值。

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

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

這個值其實是oom_score_adj的值,用這個值*17再除1000四捨五入取整數,就是對應的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

當可用內存小於318MB的時候,系統開始殺adj=15的進程,以此類推。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章