Android内存--GC的Logcat解读

本文翻译自https://developer.android.com/studio/profile/investigate-ram.html,有些话是我自己加的,便于理解,不过我不保证这些话理解错误,欢迎指正。

关于Android手机中的内存重要性就不多说了,应用开发者应该都或多或少被内存的问题折磨过,这个系列文章就把我所知的内存上的一些问题及优化记录下来,给大家一个参考。

Log分为两种:Dalvik和ART

Dalvik的Log

大家在开发过程中,在AS或者Eclipse的lotcat中会看到这样的log:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

一般来说我们不会在意这个log,但是它的确对我们是有一些意义的,我们可以从中看到GC的一些信息

它的组成:

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>

我们一个个看->->

GC_Reason

GC的原因,大概有如下几种:

1. GC_CONCURRENT

Heap快满的时候执行的并发GC

2. GC_FOR_MALLOC

程序尝试分配内存,但是Heap已经满了,这时候必须执行GC,另外,因为这时候没法分配内存,所以程序会Stop一会儿,直到内存可以分配,换句话说,这个GC不是并发的

3. GC_HPROF_DUMP_HEAP

这个是我们自己在IDE中点击Dump Heap来创建HPROF文件的时候执行的GC

4. GC_EXPLICIT

显示调用GC

5. GC_EXTERNAL_ALLOC

这个在API10以下才会调用,比如是低版本会有些Bitmap是存在Native内存中的

Amount freed

GC释放的内存数量

Heap stats

Heap内存中的分配情况,Free内存的比例 和 使用的数量/总数量

External memory stats

像上面说的,API10以下才有,额外的内存存储的数量

Pause time

堆内存越大,GC暂停时间越长,一个在GC开始的时候,一个是GC结束的时候,注意这里的暂停时间不是执行时间(具体是什么我猜想大概是会block住主线程的时间)

ART的Log

ART的GC一般来说不会打印出来,只有显示调用GC方法或者系统认为该打印的时候才会打印。

什么是系统认为该打印?就是说,如果GC的暂停时间超过5ms或者GC执行的过程超过100ms,形象点就是GC给我影响有点大了,那么它就自己打印出来告诉开发者。

ART的Log长什么样呢?举个栗子:

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

格式为:

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_Reason,看下具体含义:

1. Concurrent

感觉和上面差不多的意思,就是并发的GC,不会block住主线程,不妨碍程序分配内存

2. Alloc

同样差不多,也是在分配内存的时候内存满了,但是GC的执行在分配内存的那个线程

到这里我大胆猜想一下,Dalvik的Alloc GC是直接Block住整个程序的执行,而这里的GC,如果你是在子线程执行的分配内存操作,那么GC好像也不会影响主线程的执行(如果说错了过来打我,谢谢)。

3. Explicit

同样的,显示调用GC,但是!ART不推荐显示调用GC,因为显示调用GC会Block住分配内存的线程,而且会导致不必要的CPU周期,GC线程也有可能抢占其他应用线程从而导致Jank(这个词的意思大概类似掉帧?)

4. NativeAlloc

Native内存分配时候发生,比如Bitmap和RenderScript创建对象的时候(这段没理解,ART的Bitmap分配在Native内存中的???)

5. CollectorTransition

这段好难理解。可能需要了解一些GC的知识,我这里理解成,GC的时候会从一块内存拷贝一些对象到另一块内存(比如临时内存和存在时间较久的内存),这个过程就是CollectorTransition。另外,目前而言,CollectorTransition只可能发生在低内存的手机,应用从卡顿状态变成不卡顿(反之亦然)的这种情况

6. HomogeneousSpaceCompact

这又是一个GC算法相关的内容,一般发生在App减少内存使用或者碎片整理的时候

7. DisableMovingGc

这个不算是GC的原因,只是告诉我们在使用GetPrimitiveArrayCritical的时候GC Block住了

8. HeapTrim

这个同样不属于GC的原因,只是告诉我们GC因为内存整理Block了

GC_Name

ART中,系统有多种不同类型的GC(不同的算法)

这段实在无能为力,我记得以前看过一篇不错的文章,找不到了,贴一篇老罗的吧:http://blog.csdn.net/luoshengyang/article/details/42072975

Objects_freed/Size_freed

释放的对象数和释放的内存大小

Large_objects_freed/Large_object_size_freed

大的对象释放的数量及内存的大小

Heap stats和Pause times

不多说了

最后说一点,如果你看到你的应用有大量的GC,那么你可以看 Heap stats可以看到总内存和已分配内存,然后看下已分配的内存会不会一直增加,如果是,那么恭喜你,内存泄漏了,另外,如果你看到GC的原因是Alloc,那表明你的内存分配已经很满了,估计会OOM。

写完收工~