前言
本文用于快速理解 Android ART 的 GC 日志:涵盖日志格式与字段释义、常见 GC Reason 与收集器说明。基于真实日志的"示例与解读"一一对应解析,帮助在性能与内存问题排查中更快定位问题与优化方向。
GC日志何时会打印
- 仅当被认为是"慢 GC"时才打印:
- 暂停时间 > 5ms,或
- GC 总时长 > 100ms。
日志格式
xml
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>:触发原因<GC_Name>:收集器名称<Objects_freed>(<Size_freed>):释放对象数/字节(非大对象空间)<Large_objects_freed>(<Large_object_size_freed>):释放大对象数/字节(LOS)<Heap_stats>:堆统计(空闲百分比,已用/总)<Pause_time(s)>:暂停时间(以及总时长)
字段释义
Objects_freed:从非大对象空间回收的对象数。Size_freed:从非大对象空间回收的字节数。Large_objects_freed:从大对象空间回收的对象数。Large_object_size_freed:从大对象空间回收的字节数。Heap_stats:堆空闲百分比(已用/总)。Pause_time:暂停与 GC 期间引用变更的对象数正相关。ART 的 CMS 在结尾附近有一次短暂停;移动 GC 在多数阶段有较长停顿。
触发原因(GC Reason)
Concurrent:并发 GC;后台执行,不挂起应用线程,也不阻止分配。Alloc:堆满时分配触发;回收在发起分配的线程中执行。Explicit:显式调用(如System.gc());不建议,可能阻塞分配并造成卡顿。NativeAlloc:Native 内存压力(如 Bitmap、RenderScript)触发。CollectorTransition:收集器/堆过渡,常见于低内存设备的进程状态切换(暂停可感知 ↔ 非暂停可感知)。HomogeneousSpaceCompact:齐性空间压缩,整理碎片、降低内存占用(多见于进入暂停可感知状态)。DisableMovingGc:非真实原因;表示移动收集器被阻塞(如GetPrimitiveArrayCritical),强烈不建议使用。HeapTrim:非真实原因;表示 GC 被阻塞直至堆整理完成。
收集器名称(GC Name)
Concurrent copying (CC):ART 现代默认收集器,并发复制,暂停低;LOS(大对象空间)单独处理。Young concurrent copying:仅回收年轻代,频率高、暂停更低,适合短生命周期对象抖动场景。Concurrent mark sweep (CMS):完整堆标记-清除,非移动;在部分版本或过渡阶段仍可见。Concurrent partial mark sweep:不处理图片空间与 zygote 空间。Concurrent sticky mark sweep:仅回收自上次 GC 后新产生的垃圾,代价更低。Marksweep + semispace:非并发复制/压缩,用于堆过渡与碎片整理等场景。
示例与解读
示例 1:
scss
NativeAlloc concurrent copying GC freed 123645(7486KB) AllocSpace objects, 69(3248KB) LOS objects, 35% free, 44MB/68MB, paused 332us total 256.582ms
解读:
- 触发原因:
NativeAlloc(Native 内存压力,如 Bitmap/DirectByteBuffer/JNI)。 - 收集器:
concurrent copying。 - 释放:
123645 (7486KB);大对象69 (3248KB)。 - 堆统计:空闲
35%,已用44MB/ 总68MB。 - 时延:暂停
332us;总时长256.582ms(慢 GC)。 - 关注点:排查图片/渲染/DirectBuffer 分配与复用,核对释放与生命周期。
示例 2:
scss
Background concurrent copying GC freed 191217(10MB) AllocSpace objects, 91(22MB) LOS objects, 40% free, 35MB/59MB, paused 527us total 160.132ms
解读:
- 触发原因:
Background(后台阶段的并发回收)。 - 收集器:
concurrent copying。 - 释放:
191217 (10MB);大对象91 (22MB)。 - 堆统计:空闲
40%,已用35MB/ 总59MB。 - 时延:暂停
527us;总时长160.132ms(慢 GC)。 - 关注点:后台批量回收幅度大,观察进入后台后的内存回落是否充分。
示例 3:
scss
Background young concurrent copying GC freed 343568(21MB) AllocSpace objects, 23(696KB) LOS objects, 36% free, 34MB/55MB, paused 145us total 159.337ms
解读:
- 触发原因:
Background young(后台的 young 区回收,短生命周期对象较多)。 - 收集器:
concurrent copying。 - 释放:
343568 (21MB);大对象23 (696KB)。 - 堆统计:空闲
36%,已用34MB/ 总55MB。 - 时延:暂停
145us;总时长159.337ms(慢 GC)。 - 关注点:对象抖动明显,检查热点分配路径与缓存/池化策略。
示例 4:
scss
Explicit concurrent copying GC freed 300633(16MB) AllocSpace objects, 31(3616KB) LOS objects, 43% free, 31MB/55MB, paused 218us total 226.144ms
解读:
- 触发原因:
Explicit(显式调用,如System.gc())。 - 收集器:
concurrent copying。 - 释放:
300633 (16MB);大对象31 (3616KB)。 - 堆统计:空闲
43%,已用31MB/ 总55MB。 - 时延:暂停
218us;总时长226.144ms(慢 GC)。 - 关注点:避免在关键路径显式 GC;移除不必要的
System.gc()。
常见告警信号
- 当 Logcat 出现大量 GC 日志时,优先关注堆统计(如 31MB/55MB)。若已用/总内存比例长期走高且迟迟不回落,极可能存在内存泄漏。
- 若 GC Reason 频繁为
Alloc,说明堆空间已逼近上限,短期内极易触发 OOM,应立即排查大对象与异常分配峰值。