logcat中的GC日志
移动应用程序上的内存利用率会对客户体验产生重大影响。如果您的应用创建了很多对象,那么Android运行时(ART)环境将频繁触发垃圾回收(GC)。Android垃圾回收是一个自动过程,可从内存中删除未使用的对象。但是,频繁的垃圾回收会消耗大量CPU,并且还会暂停应用程序。频繁的停顿可能会使应用程序变得卡顿甚至ANR。
因此,如果需要了解你的应用程序正在创建多少个对象,垃圾回收的触发频率,完成垃圾回收需要花费的时间,以及在每个事件之后回收多少内存。所有这些信息都存在于运行时日志消息中。每当运行GC事件时,都会在运行时日志消息中打印一条日志行。您可以通过logcat查看这些日志行 。
这是一条典型的Android GC日志:
07-01 16:00:44.690: I/art(801): Explicit concurrent mark sweep GC freed 65595(3MB) AllocSpace objects, 9(4MB) LOS objects, 34% free, 38MB/58MB, paused 1.195ms total 87.219ms
这一条日志有多个字段。我们来简单看一下:
# | Field | Value | Description |
---|---|---|---|
1 | Timestamp | 07-01 16:00:44.690 | 运行此垃圾回收事件的时间戳。 |
2 | GC Reason | Explicit | 触发垃圾回收事件的原因。'Explicit’表示应用程序明确请求了垃圾回收,例如,通过调用 gc() 或 gc()。有关不同类型的GC原因,请参阅此处 此处。 |
3 | GC Name | concurrent mark sweep | ART具有可以运行的各种不同的GC。在这种情况下,“并发标记扫描”指示–整个堆收集器释放了空间,收集了除图像空间以外的所有空间。有关不同类型的GC名称,请参考此处。 |
4 | Objects freed | 65595(3MB) | 从非大对象空间收集的对象垃圾数量。在此事件中,共有65595个唯一对象,其累积大小为3mb,是垃圾收集(即释放)的。 |
5 | Large objects freed | 9(4MB) | 从大对象空间收集的对象垃圾数量。总共9个唯一对象,它们的累积大小为4mb,是垃圾收集(即释放)的 |
6 | Heap usage | 38MB/58MB | 在此特定的GC事件之后,38mb的对象仍然存在。此应用程序分配的堆总大小为58mb。 |
7 | GC Pause Time | 1.195ms | 在GC事件的某些阶段,应用程序被暂停。在此GC事件中,暂停时间为1.195ms。在暂停时间内,应用程序冻结。应该以低暂停时间为目标。 |
8 | GC Total Time | 87.219ms | 此GC事件完成所需的时间。它还包括GC暂停时间。 |
不同类型的GC名称
在Android运行时(ART)环境中,垃圾收集可能是以下类型之一:
# | 描述 |
---|---|
Concurrent mark sweep (CMS) | 释放整个堆的收集器将收集除图像空间以外的所有空间。 |
Concurrent partial mark sweep | 基本上是整个堆的收集器,它收集除图像和合子空间以外的所有空间。 |
Concurrent sticky mark sweep | 分代收集器,只能释放自上次GC之后分配的对象。该垃圾收集比完全或部分标记清除运行的频率更高,因为它速度更快且暂停时间更短。 |
Mark sweep + semispace | 一种非并发的复制GC,用于堆转换以及同构空间压缩(对堆进行碎片整理)。 |
不同类型的GC 原因
在Android运行时(ART)环境中,由于以下原因之一,可能会触发垃圾收集活动:
# | 描述 |
---|---|
Concurrent | 并发GC不会挂起应用程序线程。该GC在后台线程中运行,并且不会阻止分配。 |
Alloc | 启动GC是因为您的应用程序在堆已满时尝试分配内存。在这种情况下,垃圾回收发生在分配线程中。 |
Explicit | 应用程序明确请求了垃圾回收,例如,通过调用gc()。与Dalvik一样,在ART中,最佳做法是您信任GC,并尽可能避免请求显式GC。不建议使用显式GC,因为它们会阻塞分配线程并不必要地浪费CPU周期。如果显式GC导致其他线程被抢占,则它们也可能导致垃圾邮件(应用程序中的结结,颤动或暂停)。 |
NativeAlloc | 该收集是由本地分配(例如,位图或RenderScript分配对象)的本地内存压力引起的。 |
CollectorTransition | 收集是由堆转换引起的。这是由于在运行时切换GC引起的。收集器过渡包括将所有对象从自由列表支持的空间复制到凹凸指针空间(反之亦然)。当前,仅当应用程序在低RAM设备上将进程状态从暂停可感知状态更改为非暂停可感知状态(反之亦然)时,才发生收集器转换。 |
HomogeneousSpaceCompact | 同类空间压缩是自由列表空间到自由列表空间的压缩,通常在应用程序移动到无法感知的暂停过程状态时发生。这样做的主要原因是减少RAM使用率和对堆进行碎片整理。 |
DisableMovingGc | 这不是真正的GC原因,但请注意,由于使用GetPrimitiveArrayCritical,收集被阻止。同时进行并发堆压缩时。通常,强烈建议不要使用GetPrimitiveArrayCritical,因为它限制了收集器的移动。 |
HeapTrim | 这不是GC的原因,而是说明收集被阻塞直到堆修剪完成为止。 |