前言html
轉載請聲明,轉自【http://www.javashuo.com/article/p-abukqgix-gp.html】,謝謝!android
Android系統與其餘操做系統有個很不同的地方,就是其餘操做系統儘量移除再也不活動的進程,從而儘量保證多的內存空間,而Android系統倒是反其道而行之,儘量保留進程。Android這樣設計有什麼優點呢?又是經過怎樣的方法來管理這些被保留的進程的呢?Android用戶又該如何正確使用手機從而更好發揮Android系統所特有的優點呢?本文將一一爲您解開這些謎團。算法
本文的主要內容以下:小程序
1、Android進程管理的特殊設計瀏覽器
Linux系統對進程的管理方式是一旦進程活動中止,系統就會結束該進程。儘管Android基於Linux Kernel,但在進程管理上,卻採起了另一種獨特的設計:當進程活動中止時,系統並不會馬上結束它,而是會盡量地將該進程保存在內存中,在之後的某個時間,一旦須要該進程,系統就會當即打開它,而不用再作一些初始化操做。只有當剩餘內存不夠用了,爲了維持新開啓的進程或者比較重要的進程的正常運行,系統纔會選擇性地殺掉一些不重要的內存,騰出內存空間來,因此Android系統永遠不會有內存不足的提示。緩存
2、Android獨特進程管理設計的好處微信
Android這種獨特的設計,也正是Android標榜的優點之一,這有兩個好處:app
一、最大限度地提升內存的使用率。ide
好比,你的內存是8G,若是每次使用完某個進程就殺掉,那麼被使用的內存基本上會始終保持在某個值,好比4G之內,那麼內存的使用率就老是保存在50%之內,剩餘的4G內存形同虛設,發揮用處的機會很是少。而Android的這種設計,就能夠作到有多少內存就用多少內存,儘量大地提升內存使用率。一樣好比有8G內存,使用完的進程仍保留在內存中,累積下來,被使用的內存就儘量地會接近8G。post
二、提升再次啓動時的啓動速度
被駐留在內存中再也不活動的進程(後臺進程或空進程,後面會再講到),不少是常常須要使用的,當再次使用該進程的時候,系統當即打開它,而不須要再從新初始化。例如,咱們經常使用的瀏覽器,當暫時再也不使用時,按下Home鍵或Back鍵,瀏覽器進程就變成了再也不活動的進程。若是下次又要使用了,點擊多任務鍵,在最近使用應用列表中點擊瀏覽器便可,瀏覽器界面仍然保持着退出前的界面。但若是退出時把該進程移除了,那麼再次使用時,就須要從新初始化,而後進入該應用,這每每會花費很多的時間。
3、Android進程的五個等級
Android系統將盡可能長時間地保持應用進程,但爲了新建進程或運行更重要的進程,最終須要移除舊進程來回收內存。爲了肯定保留或終止哪些進程,系統會根據進程中正在運行的組件以及這些組件的狀態,將每一個進程放入「重要性層次結構」中。必要時,系統會首先消除重要性最低的進程,而後是重要性略遜的進程,以此類推,以回收系統資源。該「重要性層級結構」將進程分爲了五個等級:
一、前臺進程(foreground)
前臺進程是指那些有組件正和用戶進行交互的應用程序的進程,也稱爲Active進程。這些都是Android嘗試經過回收其餘應用程序來使其保持相應的進程。這些進程的數量很是少,只有等到最後關頭纔會終止這些進程,是用戶最不但願終止的進程。例如:而當你運行瀏覽器這類應用時,它們的界面就會顯示在前臺,它們就屬於前臺進程,當你按home鍵回到主界面,他們就變成了後臺程序。
若是一個進程知足如下任一條件,即視爲前臺進程:
(1)託管處於活動狀態的Activity,也就是說,它們位於前臺並對用戶事件進行響應,此時的情形爲響應了Activity中的onResume()生命週期方法,但沒有響應onPause()。
(2)託管正在執行onReceive()方法處理事件程序的BroadcastReceiver。
(3)託管正在執行onStart()、onCreate()或onDestroy()事件處理程序的Service。
(4)託管正在運行且被標記爲在前臺運行的Service,即調用了該Service的startForeground()方法。
(5)託管某個Service,且該Service正綁定在用戶正在交互的Activity的Service,即該Activity正處於活動狀態。
二、可見進程(visible)
沒有任何前臺組件、但仍然會影響用戶在屏幕上所見內容的進程。若是一個進程知足如下任一條件,即視爲可見進程:
(1)託管不在前臺、但仍對用戶可見的Activity(已調用其onPause()方法)。例如:若是前臺Acitivty啓動了一個對話框,或者啓動了一個非全屏,亦或是一個透明的Activity,容許在其後顯示上一個Activity,則可能會發生這種狀況,這類Activity不在前臺運行,也不能對用戶事件做出反應。
(2)託管綁定到可見Activity的Service。(官網上說是綁定到可見或前臺Activity,但筆者有一點疑問,這個和「前臺進程」中第(5)點相矛盾嗎,綁定到前臺Activity,那就是前臺進程了)
可見進程被視爲是極其重要的進程,這類進程的數量也不多,只有在資源極度匱乏的環境下,爲保證前臺進程繼續執行時纔會終止。
三、服務進程(Service)
正在運行已使用startService()方法啓動的Serice且不屬於上述兩個更高類別進程的進程。儘管服務進程與用戶所見內容沒有直接關聯,可是它們一般在執行一些用戶關心的操做。所以,除非內存不足以維持全部前臺進程和可見進程同時運行,不然系統會讓服務進程保持運行狀態。
有些資料上面也稱這種進程爲次要服務(Secondary Service),而屬於上述兩個更高類別的進程則被稱爲主要服務,主要服務每每屬於系統進程,如撥號進程等,不可能被進程管理輕易終止。這裏咱們以Android開發者官網的稱呼爲標準,稱爲服務進程。
四、後臺進程(hidden)
包含目前對用戶不可見的Activity,即該Activity調用了onStop()方法。這些進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供上述三個更高級別的進程使用。一般會有不少後臺進程在運行,它們會保存在LRU(Least Recently Used,最近最少使用)列表中,以確保包含用戶最近查看的Activity的進程最後一個被終止。若是某個Activity正確實現了生命週期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,由於當用戶導航回該Activity時,Activity會恢復其全部可見狀態。
這裏讀者能夠作個試驗,先開啓微信,進入到朋友圈界面, 而後點擊手機屏幕下方的導航欄中的Home按鍵進入到後臺,再點擊最近使用應用列表顯示按鈕(不一樣的手機位置不同,有的在Home鍵左邊,有的則在Home鍵右邊),在顯示的最近使用應用的列表中清理掉微信應用,最後再點擊桌面的微信圖標啓動微信,會發現顯示的界面仍然是朋友圈界面。
後臺進程,咱們能夠簡單理解爲,應用(只考慮只有Activity組件的狀況)啓動後按Home鍵後被切換到後臺的進程。如瀏覽器、閱讀器等,當程序顯示在屏幕上時,它們所運行的進程即爲前臺進程(foreground),一旦按home鍵(注意不是back鍵)返回到桌面,程序就停留在後臺,成爲後臺進程。
五、空進程(empty)
不含任何活動應用組件的進程。保留這種進程的惟一目的是用做緩存,以縮短下次再其中運行組件所須要的啓動時間。通常來講,當應用按back按鍵退出後應用後,就變成了一個空進程。好比BTE,在程序退出後,依然會在進程中駐留一個空進程,這個進程裏沒有任何數據在運行,做用每每是提升該程序下次的啓動速度或者記錄程序的一些歷史信息。當系統內存不夠用時,無疑,該進程是應該最早終止的。在最近使用應用列表中,能夠看到按back鍵退出的應用。
根據進程中當前活動組件的重要程度,Android會將進程評定爲它可能達到的最高級別。通俗地說,就是若是一個進程同時擁有多個對應上述不一樣等級進程的組件時,會以最高的那個等級做爲該進程的等級。例如,若是某進程託管着服務和可見Activity,則會將此進程評定爲可見進程,而不是服務進程。
此外,一個進程的級別可能會由於其餘進程對它的依賴而有所提升,即服務於另外一進程的進程其級別永遠不會低於其所服務的進程。例如,若是進程A中的內容提供程序爲進程B中的客戶端提供服務,或者若是進程A中的服務綁定到進程B中的組件,則進程A始終被視爲至少與進程B一樣重要。
因爲運行服務的進程其級別高於託管後臺Activity的進程,所以啓動長時間運行操做的Activity最好爲該操做啓動Service,而不是簡單地建立工做線程,當操做有可能比Activity更加持久時更應該如此。例如,正在將圖片上傳到網站的Activity應該啓動服務來執行上傳,這樣一來,即便用戶退出Activity,仍可在後臺繼續執行上傳操做。使用服務能夠保證,不管Activity發生什麼狀況,該操做至少具有「服務進程」優先級。若是某個Activity開啓了線程執行耗時操做,當Activity退出時,該Activity的實例將不會釋放內存資源,直到線程執行完,這樣容易致使內存泄漏。同理,廣播接收器也應該使用服務,而不是簡單地將耗時冗長的操做放入線程中。
4、進程移除順序的依據——閾(yu,第四聲)值
前面講到,內存不夠用時,會根據進程的等級來決定優先回收哪類進程。那麼系統是根據什麼來判斷須要移除這些進程的時機的呢?答案是閾值。
一、查看閾值
咱們能夠採用以下方法查看手機中各個等級進程的閾值(須要root權限),如第二排數據所示(其單位爲頁):
以第一個數據44032爲例,計算方法爲:
1page=4KB=4*1024B=4096B
44032page* 4048B/page = 180355072B
180355072B/1024/1024 = 172M
即第一個等級的進程的閾值爲172M。依次類推,閾值依次爲:172M,190M,208M,226M,316M,415M。
有必要說明一下,在Android開發者官方文檔中,是將Android應用進程分爲了5個等級,但不少資料倒是分的6個等級,在後臺進程和空進程之間還有一個「內容提供節點(content provider)進程」。內容提供節點,沒有實體程序,僅提供內容供別的程序去用 ,好比日曆供應節點,郵件供應節點等,在終止進程時,這類進程有比較高的優先權。手機中應該是採用的6個等級的方式,如上六個數據,正好對應着六個等級的進程,等級越高,閾值越低,即前臺進程閾值爲172M,空進程爲415M。當系統的剩餘內存只剩餘不到415M的時候,系統首先會回收空進程,依次類推,只有剩餘內存不到172M了,纔會去回收前臺進程,這樣就起到了優化保護重要進程的做用。
5、Home鍵、Back鍵和多任務鍵
Home鍵、Back鍵和多任務鍵,在手機屏幕的下方,這三個按鍵通常稱爲導航欄,中間的按鈕爲Home鍵,多任務鍵和Back鍵分別在其左右,通常根據手機品牌不一樣,左右位置也有所差別。
在運行App的時候,若是按一下Home鍵或者Back鍵,均可以退到桌面,那麼這二者有什麼區別呢?
後臺進程和空進程,都是駐留在後臺,處於暫停狀態,也都是除了佔用一部份內存外,不佔用其餘如cpu等資源的,那麼問題來了,爲何要設計後臺進程和空進程這兩種空進程呢?它們的區別到底在哪裏呢?咱們在前文講Android進程的5個等級的時候講到過,當剩餘內存不足的時候,系統會按照等級順序,優先移除不過重要進程,以收回內存供更重要的進程運行。那麼,它們的區別就是,在剩餘內存不足時,會優先移除空進程,再不足,纔會移除空進程。因此,若是確實要退出某個應用一段時間內不大使用了,若是這款應用有退出按鈕,就用應用自帶的退出功能;若是沒有,則最好按系統的Back鍵,這樣能夠變成空進程,當系統要回收內存時,就會優先被回收,從而釋放的所佔的資源。若是隻是暫時退出去作點別的,過一會還要切換回來,或者對這款應用使用比較頻繁,那就使用Home鍵,由於相比於按Back鍵,這樣能夠儘量保住後臺進程,方便下次使用的時候快速啓動。
固然,按Home鍵或Back鍵,對用戶來講,其實感受不到差別,使用起來沒什麼兩樣,可是,對於Android開發者來講,卻有必要做爲常識來了解其中的道理和差別。不管是按Home鍵仍是按Back鍵,在按多任務鍵的時候,均可以看到這些進程,以下圖所示。最下面的按鍵爲清理按鍵,點擊後能夠清除掉這些進程,回收內存了,固然,前面也講了不少遍了,不建議這樣作。
二、修改閾值。
能夠採用命令:echo "44032,48640,53248,57856,80896,106241" > /sys/module/lowmemorykiller/parameters/minfree來修改閾值,以下所示:
重啓後,會恢復爲原來的值。至於如何永久性修改該閾值,這裏不深刻探討,有興趣的童鞋能夠自行研究,通常來講,就按照系統給定的默認值使用就能夠了,沒特殊用途的話,不必修改。
對於這一節閾值的內容,暫時先講到這裏,若是要更深刻,能夠自行多研究研究。筆者也沒有看到比較好的更深刻的文章,因此也很差推薦,若是讀者看到比較好的,能夠推薦給筆者,感激涕零。
6、開發者選項中的進程管理功能
Android手機都帶有開發者選項,隱藏了不少功能,顧名思義,這些功能主要用於輔助開發者調試程序用的。其中有一些就是關於進程管理功能的,筆者這裏簡單介紹一下其中兩款,以下圖紅框部分所示:
7、進程管理軟件的使用
Windows操做系統用戶每每總想着保留更多的內存,在使用Android手機的時候,喜歡常常清理後臺進程或空進程,並且清理完後,內心有一種特別爽的感受,就像給家裏作了一次大掃除同樣,筆者最初使用Android手機的時候也是這樣的心態-_-!基於這樣的心態,一些進程清理軟件,很受普通用戶的青睞。其實這樣作卻正好抹殺了Android系統所標榜的優點,如前文所講到的。
那麼進程管理軟件有無必要呢?固然有的,只是須要注意使用場合。當須要運行大型程序的時候,能夠手動關閉掉一些進程,騰出足夠的空間供大型程序使用,這樣就能夠有效避免系統調用進程調度策略而引發的卡頓,這一點,第八大點第3小節中會有說明。並且因爲開發者的緣由,多是程序寫得太爛,或程序容易出錯,或作不應作的動做,或是惡意程序,對於這類程序進程,手動移除也是有好處的。
但若是是運行一些小程序,就徹底沒有必要去預先殺進程了,徹底能夠交給系統本身管理。讀者可能會疑惑,由於小程序啓動的時候,也有可能會由於內存不足而致使須要移除部分進程的狀況。筆者認爲,即使是內存不足,小程序運行引發的調用進程調度策略測的次數很是少,要移除的進程也很是少,產生的影響不大。同時,咱們也要意識到另一點就是,不管是手動殺死進程仍是自動殺進程,都須要cpu去執行這些任務,因此也會拖慢手機和消耗電量。因此從這一點看,頻繁殺進程,也是一個很差的習慣。
8、答疑解惑
在之前沒有專門去了解Android進程管理機制的時候,甚至是在研究的過程當中,筆者內心都常常存在不少疑惑,如下整理了其中5個,不知道讀者您是否有也相似的困惑呢?
一、這麼多駐留在內存的進程,不會耗電嗎?
大多數用慣了Windows操做系統的童鞋,看到Android系統儘量保留不在活動的進程的設計,可能第一反應就是質疑,難道這樣不會增長耗電量嗎?其實,但一個程序按home鍵變成後臺進程或者按back鍵退出變成空進程後,其實已經被暫停了,只保留了運行狀態,不會消耗cpu,一個程序會耗電,是由於它須要調用cpu來運算,如今不消耗cpu了,固然就不會耗電了。固然,開了service的應用就另當別論了,好比QQ音樂播放器,當按home鍵或back鍵後,音樂仍然播放,是由於它開啓了服務,並且是一個前臺服務,在後面咱們會繼續講到,此時它是一個前臺進程,而不是後臺進程或空進程。
二、爲何一個不太app,運行時會佔用很大的內存呢?
咱們常常會碰到這樣一種現象,一個只有20M的App,運行起來的時候,卻會耗掉100M以上的內存。一方面是,程序運行時爲對象分配內存,另外一方面,是Android虛擬機的緣由。Android中的應用啓動的時候,系統都會給它開啓一個獨立的虛擬機,這樣作的好處是能夠避免虛擬機崩潰致使整個系統崩潰(此處能夠參考筆者之前的文章:【朝花夕拾】Android性能篇之(五)Android虛擬機),代價就是耗用更多的內存。
三、爲何內存少的時候,運行大型程序會卡頓呢?
當剩餘內存很少時,打開大型程序,系統會觸發自身的進程調度策略,去移除一些等級比較低的進程來回收內存,以供大型程序運行。而這個進程調度策略在決定哪些進程須要被移除的過程,是一個十分消耗資源的操做,特別是一個程序頻繁像系統申內存的時候,這樣就致使了系統的卡頓。
四、應用開得太多了,手機變慢,是由於內存被佔用太多嗎?
其實手機變慢的根本緣由是cpu被耗用太多,而不是內存佔用太多,由於真正執行程序所要完成的任務的最終執行者是CPU,而不是內存(RAM)。在內存足夠的狀況下,若是系統中佔用cpu的進程太多,那無疑cpu總有忙不過來的時候,那確定就會變慢了。這就比如,在一條道路上駕車,道路就像內存,車的引擎就像cpu,若是車的引擎的動力不夠,或者承載的貨物太多,車都跑不快,即使是道路上一路暢通無阻,也無濟於事。因此,內存佔用多少並不重要,只要道路提供給車輛前行的空間是足夠的,手機變慢的責任,就和內存無關了。這個比喻用來解釋第三點也很恰當,道路提供的車輛前進的空間沒法知足車輛所必需的空間時,就須要交通機制花時間來調節交通,給這輛車提供足夠的空間,而在此期間,這輛車只能乖乖候着。
五、Android手機越用越慢,是什麼緣由呢?
Android手機經常是越用越慢,即便是恢復出廠設置,也沒法改變這個現象。手機越用越慢,主要由以下幾個緣由:(1)虛擬機機制問題。這一點在上一個問題中也提到了,在Android4.4之前的系統,使用的是Dalvik虛擬機,它的設計機制有缺陷,就是越用越慢;在Android4.4系統中有切換按鈕,能夠在Art虛擬機和Dalvik虛擬機之間切換;在Android4.4之後的系統就完全拋棄了Dalvik而全面使用Art(讀者能夠參考:【朝花夕拾】Android性能篇之(五)Android虛擬機)。(2)開啓了太多的服務,致使耗用太多的CPU。隨着手機開機使用時間的增加,應用使用愈來愈多,不少應用看似退出了,而其實後臺可能開了很多的服務,而他們可能尚未關閉。這些服務正在執行一些操做,會消耗CPU,而CPU纔是手機變慢的根本緣由。 並且Android app比較開放的,有不少不良應用充斥其中,可能對服務處理不當,濫用服務等,增長系統中的服務。(3)系統頻繁調用自身的進程調度算法。這一點在前面已經說明了,這裏再也不贅述。(4)手機硬件的天然老化。這一點請閱讀:手機越用越慢?魯大師老化實驗室告訴你真相 。
本文的內容主要來源於Anroid官方開發網站、各類技術博客、以及本身的實際操做總結,在整理這方面知識的過程當中,也漸漸解開了很多曾經的疑惑,對Android系統有了更多的認識。本文中筆者在不斷強調,不要常常性地殺進程,主要是廣大的朋友們受Windows操做系統的毒害太深,一時難以改變舊有的觀念,因此不得不囉囉嗦嗦一再提起,以圖增強讀者的認識。受限於文章篇幅和筆者的知識,本文沒有更深刻地從源碼角度去分析,更多地是在普及Android進程管理機制方面的基礎知識。若是文章中有不當或不正確的地方,請讀者不吝賜教,也更但願這篇文章能幫助更多的人提升多Android的認識,謝謝!
推薦閱讀