在Android系统中,GC有三种类型:
kGcCauseForAlloc:分配内存不够引起的GC,会Stop World。由于是并发GC,其它线程都会停止,直到GC完成。
kGcCauseBackground:内存达到一定阈值触发的GC,由于是一个后台GC,所以不会引起Stop World。
kGcCauseExplicit:显示调用时进行的GC,当ART打开这个选项时,使用System.gc时会进行GC。
接下来,我们来学会如何分析Android虚拟机中的GC日志,日志如下:
D/dalvikvm(7030):GC_CONCURRENT freed 1049K, 60% free 2341K/9351K, external 3502K/6261K, paused 3ms 3ms
GC_CONCURRENT 是当前GC时的类型l,GC日志中有以下几种类型:
-
GC_CONCURRENT
:当应用程序中的Heap内存占用上升时(分配对象大小超过384k),避免Heap内存满了而触发的GC。如果发现有大量的GC_CONCURRENT出现,说明应用中可能一直有大于384k的对象被分配,而这一般都是一些临时对象被反复创建,可能是对象复用不够所导致的。 -
GC_FOR_MALLOC
:这是由于Concurrent GC没有及时执行完,而应用又需要分配更多的内存,这时不得不停下来进行Malloc GC。 -
GC_EXTERNAL_ALLOC
:这是为external分配的内存执行的GC。 -
GC_HPROF_DUMP_HEAP
:创建一个HPROF profile的时候执行。 -
GC_EXPLICIT
:显示调用了System.GC()。(尽量避免)
我们再回到上面打印的日志:
- freed 1049k:表明在这次GC中回收了多少内存。
- 60% free 2341k/9351K:表明回收后60%的Heap可用,存活的对象大小为2341kb,heap大小是9351kb。
- external 3502/6261K:是Native Memory的数据。存放Bitmap Pixel Data(位图数据)或者堆以外内存(NIO Direct Buffer)之类的数据。第一个值说明在Native Memory中已分配3502kb内存,第二个值是一个浮动的GC阈值,当分配内存达到这个值时,会触发一次GC。
- paused 3ms 3ms:表明GC的暂停时间,如果是Concurrent GC,会看到两个时间,一个开始,一个结束,且时间很短,如果是其他类型的GC,很可能只会看到一个时间,且这个时间是相对比较长的。并且,越大的Heap Size在GC时导致暂停的时间越长。
在Dalvik虚拟机下,GC的操作都是并发的,也就意味着每次触发GC都会导致其它线程暂停工作(包括UI线程)。
在ART模式下,GC时不像Dalvik仅有一种回收算法,ART在不同的情况下会选择不同的回收算法,比如Alloc内存不够时会采用非并发GC,但在Alloc后,发现内存达到一定阈值时又会触发并发GC。所以在ART模式下,并不是所有的GC都是非并发的。
在GC方面,与Dalvik相比,ART更为高效,不仅仅是GC的效率,大大地缩短了Pause时间,而且在内存分配上对大内存分配单独的区域,还能有算法在后台做内存整理,减少内存碎片。因此,在ART虚拟机下,可以避免较多的类似GC导致的卡顿问题。