Android中的Serializable、Parcelable">Android中的Serializable、Parcelable
1178
2022-05-30
推薦資源站:https://zhimalier.com/
在Android中,默認情況下,同一應用的所有組件均運行在同一進程中,且大多數應用都不會改變這一點。不過,單進程開發并不是Android應用的全部,今天我們就來說說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的進程,以此類推。
小結
以上,我們大概了解了一下Android進程、多進程、生命周期以及Low Memory Killer的相關知識。至于如何運用到實際開發當中,我們在下一篇文章《Android多進程使用場景》中繼續探討。
Android HTTP 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。