前言
本文用于快速理解 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,应立即排查大对象与异常分配峰值。