Android 內存優化(二)DVM 和 ART 的 GC 日誌分析

相關文章
Android內存優化系列
Java虛擬機系列javascript

前言

Java虛擬機(三)垃圾標記算法與Java對象的生命週期這篇文章中,提到了Java虛擬機的GC日誌。DVM和ART的GC日誌與Java虛擬機的日誌有較大的區別,這篇文章就對DVM和ART的GC日誌進行分析。
html

1.DVM的GC日誌

在 DVM 中,每次垃圾收集都會將GC日誌打印到 logcat 中,具體的格式爲:java

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>複製代碼

能夠看到DVM的日誌共有5個信息,其中GC Reason有不少種,這裏將它單獨拿出來進行介紹。android

引發GC緣由

GC Reason就是指引發GC緣由,有如下幾種:算法

  • GC_CONCURRENT:當堆開始填充時,併發GC能夠釋放內存。
  • GC_FOR_MALLOC:當堆內存已滿時,app嘗試分配內存而引發的GC,系統必須中止app並回收內存。
  • GC_HPROF_DUMP_HEAP:當你請求建立 HPROF 文件來分析堆內存時出現的GC。
  • GC_EXPLICIT:顯示的GC,例如調用System.gc()(應該避免調用顯示的GC,信任GC會在須要時運行)。
  • GC_EXTERNAL_ALLOC:僅適用於 API 級別小於等於10 ,用於外部分配內存的GC。

其餘信息

除了引發GC緣由,其餘的信息爲:微信

  • Amount_freed:本次GC釋放內存的大小。
  • Heap_stats:堆的空閒內存百分比 (已用內存)/(堆的總內存)。
  • External_memory_stats:API 級別 10 及更低級別的內存分配 (已分配的內存)/(引發GC的閥值)。
  • Pause time:暫停時間,更大的堆會有更長的暫停時間。併發暫停時間顯示了兩個暫停:一個出如今垃圾收集開始時,另外一個出如今垃圾收集快要完成時。

實例分析

D/dalvikvm: GC_CONCURRENT freed 2012K, 63% free 3213K/9291K, external 4501K/5161K, paused 2ms+2ms複製代碼

這個GC日誌的含義爲:引發GC的緣由是GC_CONCURRENT;本次GC釋放的內存爲2012K;堆的空閒內存百分比爲63%,已用內存爲3213K,堆的總內存爲9291K;暫停的總時長爲4ms。併發

2.ART的GC日誌

ART的GC日誌與DVM不一樣,ART 不會爲沒有明確請求的垃圾收集打印GC日誌。只有在認爲GC速度慢時纔會打印GC日誌,更確切來講,僅在GC暫停超過5ms 或GC持續時間超過 100ms 時纔會打印GC日誌。若是app未處於可察覺的暫停進程狀態,那麼它的GC不會被認爲是慢速的。ART的GC日誌始終會記錄顯式的垃圾收集。app

ART的GC日誌具體的格式爲:jvm

I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects,
 <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>複製代碼

引發GC緣由

ART的引發GC緣由(GC_Reason)要比DVM多一些,有如下幾種:優化

  • Concurrent: 併發GC,不會使App的線程暫停,該GC是在後臺線程運行的,並不會阻止內存分配。
  • Alloc:當堆內存已滿時,App嘗試分配內存而引發的GC,這個GC會發生在正在分配內存的線程。
  • Explicit:App顯示的請求垃圾收集,例如調用System.gc()。與DVM同樣,最佳作法是應該信任GC並避免顯示的請求GC,顯示的請求GC會阻止分配線程並沒必要要的浪費 CPU 週期。若是顯式的請求GC致使其餘線程被搶佔,那麼有可能會致使 jank(App同一幀畫了屢次)。
  • NativeAlloc:Native內存分配時,好比爲Bitmaps或者RenderScript分配對象, 這會致使Native內存壓力,從而觸發GC。
  • CollectorTransition:由堆轉換引發的回收,這是運行時切換GC而引發的。收集器轉換包括將全部對象從空閒列表空間複製到碰撞指針空間(反之亦然)。當前,收集器轉換僅在如下狀況下出現:在內存較小的設備上,App將進程狀態從可察覺的暫停狀態變動爲可察覺的非暫停狀態(反之亦然)。
  • HomogeneousSpaceCompact:齊性空間壓縮是指空閒列表到壓縮的空閒列表空間,一般發生在當App已經移動到可察覺的暫停進程狀態。這樣作的主要緣由是減小了內存使用並對堆內存進行碎片整理。
  • DisableMovingGc:不是真正的觸發GC緣由,發生併發堆壓縮時,因爲使用了 GetPrimitiveArrayCritical,收集會被阻塞。通常狀況下,強烈建議不要使用 GetPrimitiveArrayCritical,由於它在移動收集器方面具備限制。
  • HeapTrim:不是觸發GC緣由,可是請注意,收集會一直被阻塞,直到堆內存整理完畢。

垃圾收集器名稱

GC_Name指的是垃圾收集器名稱,有如下幾種:

  • Concurrent mark sweep (CMS):CMS收集器是一種以獲取最短收集暫停時間爲目標收集器,採用了標記-清除算法(Mark-Sweep)實現。 它是完整的堆垃圾收集器,能釋放除了Image Space以外的全部的空間。
  • Concurrent partial mark sweep:部分完整的堆垃圾收集器,能釋放除了Image Space和Zygote Spaces以外的全部空間。關於Image Space和Zygote Spaces能夠查看Android內存優化(一)DVM和ART原理初探這篇文章。
  • Concurrent sticky mark sweep:分代收集器,它只能釋放自上次GC以來分配的對象。這個垃圾收集器比一個完整的或部分完整的垃圾收集器掃描的更頻繁,由於它更快而且有更短的暫停時間。
  • Marksweep + semispace:非併發的GC,複製GC用於堆轉換以及齊性空間壓縮(堆碎片整理)。

其餘信息

  • Objects freed:本次GC從非Large Object Space中回收的對象的數量。
  • Size_freed:本次GC從非Large Object Space中回收的字節數。
  • Large objects freed: 本次GC從Large Object Space中回收的對象的數量。
  • Large object size freed:本次GC從Large Object Space中回收的字節數。
  • Heap stats:堆的空閒內存百分比 (已用內存)/(堆的總內存)。
  • Pause times:暫停時間,暫停時間與在GC運行時修改的對象引用的數量成比例。目前,ART的CMS收集器僅有一次暫停,它出現GC的結尾附近。移動的垃圾收集器暫停時間會很長,會在大部分垃圾回收期間持續出現。

實例分析

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 
21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms複製代碼

這個GC日誌的含義爲:引發GC緣由是Explicit ;垃圾收集器爲CMS收集器;釋放對象的數量爲104710個,釋放字節數爲7MB;釋放大對象的數量爲21個,釋放大對象字節數爲416KB;堆的空閒內存百分比爲33%,已用內存爲25MB,堆的總內存爲38MB;GC暫停時長爲1.230ms,GC總時長爲67.216ms。

參考資料
Investigating Your RAM Usage


歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。

相關文章
相關標籤/搜索