Android Runtime(ART) GC 日志手册

前言

本文用于快速理解 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)

  1. Concurrent:并发 GC;后台执行,不挂起应用线程,也不阻止分配。
  2. Alloc:堆满时分配触发;回收在发起分配的线程中执行。
  3. Explicit:显式调用(如 System.gc());不建议,可能阻塞分配并造成卡顿。
  4. NativeAlloc:Native 内存压力(如 Bitmap、RenderScript)触发。
  5. CollectorTransition:收集器/堆过渡,常见于低内存设备的进程状态切换(暂停可感知 ↔ 非暂停可感知)。
  6. HomogeneousSpaceCompact:齐性空间压缩,整理碎片、降低内存占用(多见于进入暂停可感知状态)。
  7. DisableMovingGc:非真实原因;表示移动收集器被阻塞(如 GetPrimitiveArrayCritical),强烈不建议使用。
  8. HeapTrim:非真实原因;表示 GC 被阻塞直至堆整理完成。

收集器名称(GC Name)

  1. Concurrent copying (CC):ART 现代默认收集器,并发复制,暂停低;LOS(大对象空间)单独处理。
  2. Young concurrent copying:仅回收年轻代,频率高、暂停更低,适合短生命周期对象抖动场景。
  3. Concurrent mark sweep (CMS):完整堆标记-清除,非移动;在部分版本或过渡阶段仍可见。
  4. Concurrent partial mark sweep:不处理图片空间与 zygote 空间。
  5. Concurrent sticky mark sweep:仅回收自上次 GC 后新产生的垃圾,代价更低。
  6. 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,应立即排查大对象与异常分配峰值。
相关推荐
Kapaseker6 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴6 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭16 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab17 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋1 天前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter