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,应立即排查大对象与异常分配峰值。
相关推荐
FrameNotWork4 分钟前
Android Repo Manifest 文件详解(基于 Redroid 定制示例)
android
沐怡旸1 小时前
【底层机制】Android OTA更新系统:原理与应用深度解析
android·面试
q***31142 小时前
【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之后端环境搭建
android·前端·后端
SkyQvQ3 小时前
Android Studio 开发效率神器:Auto-import
android·android studio
木子予彤4 小时前
Compose 中的系统区域适配
android·android jetpack
q***72194 小时前
Y20030018基于Java+Springboot+mysql+jsp+layui的家政服务系统的设计与实现 源代码 文档
android·前端·后端
Code Warrior4 小时前
【MySQL数据库】数据类型
android·数据库·mysql
a***13146 小时前
python的sql解析库-sqlparse
android·前端·后端
r***86986 小时前
mysql的主从配置
android·mysql·adb
.豆鲨包6 小时前
【Android】深入理解Activity的生命周期和IntentFilter
android·java