Android在4.4以前一直使用的Dalvik虛擬機做爲App的運行VM的, 4.4中引入了ART做爲開發者備選, 5.0起正式將ART做爲默認VM了.html
咱們首先來簡單瞭解下兩者:android
若是隻是想簡單瞭解, 我的以爲百度百科上這個Dalvik的介紹基本就知足要求了.shell
若是你們想深刻, 能夠看下老羅的Android之旅中Dalvik的相關博文, 從代碼層面上分析了Dalvik的啓動, 運行機制等. 值得一看.緩存
須要說明的是, Dalvik採用的是JIT技術, 在應用程序啓動時, JIT經過進行連續的性能分析來優化程序代碼的執行, 在程序運行的過程當中, Dalvik在不斷的進行將字節碼編譯成機器碼的工做.bash
ART 取自 Android RunTime. Android用其取代Dalvik, 主要目的就是爲了提高運行性能. 因此, ART相比Dalvik有幾個關鍵的提高:網絡
在安裝apk的過程當中, ART會使用dex2oat程序全部的字節碼預編譯成了機器碼. 應用程序運行過程當中無需進行實時的編譯工做, 只須要進行直接調用. 故而提升了應用程序的運行效率.併發
ART和Dalvik都是使用paging和memory-mapping(mmapping)來管理內存的. 這就意味着, 任何被分配的內存都會持續存在, 惟一的釋放這塊內存的方式就是釋放對象引用(讓對象GC Root不可達), 故而讓GC程序來回收內存.app
對於每一個App進程來講, Heap內存被限制在一個虛擬的內存區間內. 且定義了邏輯上的使用的Heap Size, 這個Heap Size在系統限制的最大值以內是隨着應用的使用狀況而變化的.函數
Heap內存的邏輯大小和實際物理內存的大小是不相同的. 後面咱們在使用Memory Monitor等內存分析工具分析內存時, 會看到一個叫作Proportional Set Size (PSS)的值, 這個值纔是系統認爲的你的App所佔用的物理內存大小.工具
這個PSS值也就是實際物理內存大小, 統計包括了你的應用進程所佔用的內存大小, 和共享內存中佔用的內存大小(比例分配方式計算).
Android VM不會壓縮Heap內存的邏輯大小, 故而沒法經過碎片整理的方式來釋放Heap空間, 而只能經過回收Heap尾部的空內存塊來壓縮邏輯內存大小.
這時, 咱們的GC就出場了, GC以後, VM會遍歷Heap找到不被使用的pages, 經過madvise函數將其返回給內核, 從而釋放這塊被邏輯Heap使用的物理內存.
Android是一個多任務系統, 爲了保證多任務的運行, Android給每一個App可以使用的Heap大小設定了一個限定值.
這個值是系統設置的prop值, 系統編譯時內置的, 保存在system/build.prop中. 通常國內的手機廠商都會作修改, 根據手機配置不一樣而不一樣, 能夠經過以下命令查看:
$ adb shell shell@hwH60:/ $ cat /system/build.prop
以手頭的Huawei 榮耀6爲例, heap size相關的prop以下:
dalvik.vm.heapstartsize=8m dalvik.vm.heapgrowthlimit=192m dalvik.vm.heapsize=512m dalvik.vm.heaptargetutilization=0.75 dalvik.vm.heapminfree=2m dalvik.vm.heapmaxfree=8m
其中:
dalvik.vm.heapstartsize
-- App啓動後, 系統分配給它的Heap初始大小. 隨着App使用可增長.
dalvik.vm.heapgrowthlimit
-- 默認狀況下, App可以使用的Heap的最大值, 超過這個值就會產生OOM.
dalvik.vm.heapsize
-- 若是App的manifest文件中配置了largeHeap屬性, 以下.則App可以使用的Heap的最大值爲此項設定值.
<application android:largeHeap="true"> ... </application>
dalvik.vm.heaptargetutilization
-- 當前理想的堆內存利用率. GC後, Dalvik的Heap內存會進行相應的調整, 調整到當前存活的對象的大小和 / Heap大小 接近這個選項的值, 即這裏的0.75. 注意, 這只是一個參考值.
dalvik.vm.heapminfree
-- 單次Heap內存調整的最小值.
dalvik.vm.heapmaxfree
-- 單次Heap內存調整的最大值.
也能夠直接使用getprop查看單項prop:
$ adb shell getprop dalvik.vm.heapsize 512m
Android 系統會盡量長時間地保持應用進程, 但爲了新建進程或運行更重要的進程, 最終須要清除舊進程來回收內存. 爲了肯定保留或終止哪些進程, 系統會根據進程中正在運行的組件以及這些組件的狀態, 將每一個進程設定了一個重要級別. 必要時, 系統會首先消除重要性最低的進程, 而後是重要性略低的進程, 依此類推, 以回收系統資源.
依據重要程度從大到小依次分爲5級:
前臺進程
用戶當前操做所必需的進程. 若是一個進程知足如下任一條件, 即視爲前臺進程:
只有在內在不足以支持它們同時繼續運行這一萬不得已的狀況下,系統纔會終止它們。 此時,設備每每已達到內存分頁狀態,所以須要終止一些前臺進程來確保用戶界面正常響應。
可見進程
沒有任何前臺組件、但仍會影響用戶在屏幕上所見內容的進程。 若是一個進程知足如下任一條件,即視爲可見進程:
服務進程
正在運行已使用 startService() 方法啓動的服務且不屬於上述兩個更高類別進程的進程。儘管服務進程與用戶所見內容沒有直接關聯,可是它們一般在執行一些用戶關心的操做(例如,在後臺播放音樂或從網絡下載數據)。所以,除非內存不足以維持全部前臺進程和可見進程同時運行,不然系統會讓服務進程保持運行狀態。
後臺進程
包含目前對用戶不可見的 Activity 的進程(已調用 Activity 的 onStop() 方法)。這些進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供前臺進程、可見進程或服務進程使用。 一般會有不少後臺進程在運行,所以它們會保存在 LRU (最近最少使用)列表中,以確保包含用戶最近查看的 Activity 的進程最後一個被終止。若是某個 Activity 正確實現了生命週期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,由於當用戶導航回該 Activity 時,Activity 會恢復其全部可見狀態。
空進程
不含任何活動應用組件的進程。保留這種進程的的惟一目的是用做緩存,以縮短下次在其中運行組件所需的啓動時間。 爲使整體系統資源在進程緩存和底層內核緩存之間保持平衡,系統每每會終止這些進程。
當用戶切換App時, 被切換到後臺的App所使用的內存並未所以刪除, 該App進程被緩存到一個LRU緩存中, 以便用戶切換回來時, 能更快的啓動App, 讓多任務更流暢.
可是, 當系統內存不夠用的時候, 就會根據LRU特性, 以及上面說到的進程級別(同時也會考慮該App進程佔用的內存大小)來決定殺死哪些進程, 來回收內存, 以便執行當前任務.
因此, 若是咱們爲了避免要讓系統kill掉咱們的App, 能夠從進程級別, 內存消耗量等幾個方面進行優化.
本文加上GC那些事兒, 咱們講了兩篇的理論知識, 相信你們對Android的內存管理有了個大致的瞭解, 後面將介紹一些內存分析工具以及使用, 結合實際來講明怎麼分析內存問題.