正确理解内存回收log信息
当系统发生内存回收,会有logcat信息。那么如何正确理解内存回收信息呢?有两种类型的回收信息log:虚拟机时代的log和ART时代的log虚拟机时代的log每次产生GC时间,log格式如下:D/dalvikvm(PID): GC_Reason Amount_freed, Heap_stats, External_memory_stats, Pause_time示例:D/dalvikvm( 905
当系统发生内存回收,会有logcat信息。
那么如何正确理解内存回收信息呢?
有两种类型的回收信息log:虚拟机时代的log和ART时代的log
虚拟机时代的log
每次产生GC时间,log格式如下:
D/dalvikvm(PID): GC_Reason Amount_freed, Heap_stats, External_memory_stats, Pause_time
示例:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
格式解析:
GC_Reason
- GC_CONCURRENT
当堆开始填满时触发并发GC,回收内存 - GC_FOR_MALLOC
当应用尝试分配内存时,此时堆已经用完,系统不得不停止app和回收内存。 - GC_HPROF_DUMP_HEAP
当请求创建一个HPROF文件(用于分析内存),触发GC。 - GC_EXPLICIT
代码中明确的调用gc()(不建议如此使用) - GC_EXTERNAL_ALLOC
这种内存回收在API版本为10及更小的版本发生。
Amount freed
本次回收的内存大小
Heap stats
堆内存状态:空闲堆内存百分比和使用中的对象数/堆内存总大小
External memory stats
在API 10及之下版本,外部分配占用的堆内存大小/外部分配最大限制内存大小。
Pause time
大的堆栈会有更长停顿时间。log显示两个停顿时间:开始回收时的停顿时间和结束时的停顿时间。
内存回收的log收集起来,查找堆状态的增长信息(3571K/9991K),如果一直在增长,可能存在内存泄漏。
ART时代log
不像虚拟机,ART不会记录非明确调用执行的GC。GC被打印仅仅是因为认为运行慢了。更准准确的说,GC停顿超过5ms或者GC过程停顿超过100ms。如果app没有处于可察觉停顿状态(如后台运行),那么没有GC被认为是慢的。确定的GC调用总会被记录。
ART的内存回收包含以下信息
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)
例如
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 Reason
什么触发了GC和回收了什么?原因如下
- Concurrent
并发GC不会阻塞app线程。该GC运行在后台线程且不会阻止内存申请。 - Alloc
该GC被发起,是因为在堆内存已经申请使用完后再次申请内存。这种情况,GC运行在内存申请的线程。 - Explicit
内存回收被app直接的请求执行,例如,调用gc()。类似虚拟机,ART中最好的使用时详细系统GC,尽量避免直接调用GC。直接调用GC不鼓励使用,因为直接调用会阻塞申请内存的线程和不必要的浪费CPU时间片。直接调用GC,其他线程被抢占,也会导致无法预料的异常(如卡顿、抖动、停止运行)。 - NativeAlloc
本地内存申请存在压力,如Bitmaps或者渲染申请内存,会触发内存回收。 - CollectorTransition
回收被堆管理策略转换导致的。在运行时改变GC策略,触发GC(例如在app可察觉停顿状态下,app改变GC策略)。回收策略转换包括将所有对象从free-list backed space拷贝到 bump pointer space (or visa versa)。 - HomogeneousSpaceCompact
同构空间压缩是指从空闲列表空间到空闲列表空间的压缩,通常发生在应用程序移动到一个难以察觉的暂停进程状态时。这样做的主要原因是减少RAM的使用和整理堆的碎片。 - DisableMovingGc
这不是一个真正的GC事件原因,但需要注意的是,回收会因为调用GetPrimitiveArrayCritical
被阻塞。当并发堆压缩发生时。一般情况下,强烈不鼓励使用GetPrimitiveArrayCritical,因为它对移动收集器有限制。 - HeapTrim
这不是一个真正的GC事件原因,但需要注意的是,回收会被阻塞指导堆内存被整理完成。
GC Name
ART有多种不同的GC可被执行。
- Concurrent mark sweep (CMS)
收集回收整个堆内存除了图像部分内存。 - Concurrent partial mark sweep
几乎全堆收集,收集除了图像和zygote以外的所有空间。 - Concurrent sticky mark sweep
分代收集器,只能释放自上次GC以来分配的对象。这种垃圾收集比完全或部分标记清理运行得更频繁,因为它速度更快,暂停时间更短。 - Marksweep + semispace
非并发的、复制的GC,用于堆转换和同质空间压缩(以整理堆的碎片)。
Objects freed
本次回收,从非大对象空间回收的对象数。
Sized freed
本次回收,从非大对象空间回收的字节数
Large Object freed
本次回收,从大对象空间回收的对象数
Heap stats
剩余堆内存百分比,使用中的对象数/整个堆大小。
Pause times
一般来说,停顿时间与GC运行时修改的对象引用的数量成比例。目前,ART CMS的GCs只有一次停顿,在GC快结束的时候。运行的GC有一个很长的停顿,在大部分GC持续时间中都是如此。
如果在log中看到大量的GC事件,关注堆状态增长的变化(如上例中的25MB/38MB)。如果堆使用一直在增长,不曾变小过,那么可能存在内存泄漏。另外,如果看到的GC都是因为“Alloc”触发的,那么app运行在一个接近所有堆容量的状态,在不久就会出现OOM的情况。
更多推荐
所有评论(0)