Android ART虚拟机中GC机制的三个参数:GcCause(触发原因)、GcType(回收类型)、CollectorType(垃圾回收器类型)
概念 | 代表枚举 | 作用 |
---|---|---|
触发原因 | GcCause | 描述 为何需要 GC(如分配失败、显式调用、后台清理等) |
回收类型 | GcType | 定义 GC 的范围与策略(如局部回收、全堆回收、粘性回收等) |
执行方式 | CollectorType | 指定 具体回收算法实现(如并发标记、压缩复制、虚拟操作等) |
在ART虚拟机中,很多场景都会触发垃圾回收的执行:
一、GcCause(GC触发原因):
# /art/runtime/gc/gc_cause.h
28 enum GcCause {
29 // Invalid GC cause used as a placeholder.
30 kGcCauseNone,
31 // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
32 // retrying allocation.
33 kGcCauseForAlloc,
34 // A background GC trying to ensure there is free memory ahead of allocations.
35 kGcCauseBackground,
36 // An explicit System.gc() call.
37 kGcCauseExplicit,
38 // GC triggered for a native allocation when NativeAllocationGcWatermark is exceeded.
39 // (This may be a blocking GC depending on whether we run a non-concurrent collector).
40 kGcCauseForNativeAlloc,
41 // GC triggered for a collector transition.
42 kGcCauseCollectorTransition,
43 // Not a real GC cause, used when we disable moving GC (currently for GetPrimitiveArrayCritical).
44 kGcCauseDisableMovingGc,
45 // Not a real GC cause, used when we trim the heap.
46 kGcCauseTrim,
47 // Not a real GC cause, used to implement exclusion between GC and instrumentation.
48 kGcCauseInstrumentation,
49 // Not a real GC cause, used to add or remove app image spaces.
50 kGcCauseAddRemoveAppImageSpace,
51 // Not a real GC cause, used to implement exclusion between GC and debugger.
52 kGcCauseDebugger,
53 // GC triggered for background transition when both foreground and background collector are CMS.
54 kGcCauseHomogeneousSpaceCompact,
55 // Class linker cause, used to guard filling art methods with special values.
56 kGcCauseClassLinker,
57 // Not a real GC cause, used to implement exclusion between code cache metadata and GC.
58 kGcCauseJitCodeCache,
59 // Not a real GC cause, used to add or remove system-weak holders.
60 kGcCauseAddRemoveSystemWeakHolder,
61 // Not a real GC cause, used to prevent hprof running in the middle of GC.
62 kGcCauseHprof,
63 // Not a real GC cause, used to prevent GetObjectsAllocated running in the middle of GC.
64 kGcCauseGetObjectsAllocated,
65 // GC cause for the profile saver.
66 kGcCauseProfileSaver,
67 // GC cause for deleting dex cache arrays at startup.
68 kGcCauseDeletingDexCacheArrays,
69 };
- 常规内存管理相关
枚举值 | 触发场景 | 说明 |
---|---|---|
kGcCauseForAlloc | 分配对象时堆空间不足 | 最常见的GC原因,由内存分配失败触发 |
kGcCauseBackground | 后台GC线程主动释放内存,预防未来分配失败 | 非阻塞式GC,避免应用卡顿 |
kGcCauseForNativeAlloc | Native内存分配超过阈值(NativeAllocationGcWatermark) | 可能阻塞,取决于GC策略 |
kGcCauseCollectorTransition | GC策略切换(如从年轻代收集器切换到老年代收集器) | 确保堆状态适应新收集器 |
kGcCauseHomogeneousSpaceCompact | CMS收集器下空间压缩(仅当前后台均使用CMS时) | 优化堆碎片 |
- 系统主动调用
枚举值 | 触发场景 | 说明 |
---|---|---|
kGcCauseExplicit | 显式调用System.gc() | 开发者主动触发,可能被忽略(依赖DisableExplicitGC配置) |
kGcCauseProfileSaver | 性能分析器(Profiler)保存数据时触发 | 优化性能分析过程 |
- 特殊控制与调试
枚举值 | 触发场景 | 说明 |
---|---|---|
kGcCauseDisableMovingGc | 禁用移动式GC(如GetPrimitiveArrayCritical调用期间) | 非真正GC,仅暂停压缩避免内存移动 |
kGcCauseTrim | 堆内存压缩(Heap Trim) | 非真正GC,释放未使用物理内存 |
kGcCauseDebugger | 调试器附加时暂停GC | 非真正GC,避免调试断点与GC冲突 |
kGcCauseGetObjectsAllocated | 调用GetObjectsAllocated统计对象数前暂停GC | 非真正GC,确保统计准确性 |
- 启动与关闭阶段
枚举值 | 触发场景 | 说明 |
---|---|---|
kGcCauseClassLinker | 类加载器初始化(如填充Art方法) | 保护关键内存操作 |
kGcCauseDeletingDexCacheArrays | 启动时删除Dex缓存数组 | 优化启动内存 |
kGcCauseStartup | ART虚拟机启动期间 | 初始化堆状态 |
kGcCauseExit | 应用退出时释放资源 | 清理堆残留对象 |
- 工具与诊断
枚举值 | 触发场景 | 说明 |
---|---|---|
kGcCauseHprof | 生成HPROF堆转储文件前触发GC | 确保转储数据一致性 |
kGcCauseJit | JIT编译器内存分配失败 | 编译代码时触发GC |
- 占位与无效值
枚举值 | 说明 |
---|---|
kGcCauseNone | 无效占位符(无实际GC触发) |
kGcCauseAlways | 保留值,未实际使用 |
二、GcType(GC回收类型):
# /art/runtime/gc/collector/gc_type.h
enum GcType {
31 // Placeholder for when no GC has been performed.
32 kGcTypeNone,
33 // Sticky mark bits GC that attempts to only free objects allocated since the last GC.
34 kGcTypeSticky,
35 // Partial GC that marks the application heap but not the Zygote.
36 kGcTypePartial,
37 // Full GC that marks and frees in both the application and Zygote heap.
38 kGcTypeFull,
39 // Number of different GC types.
40 kGcTypeMax,
41 };
GcType Enum | 作用 | 场景 |
---|---|---|
kGcTypeNone | 表示未执行任何 GC 的占位符状态,不触发实际回收。 | 虚拟机启动后尚未进行 GC 时的初始状态,或作为 GC 统计的基准值。 |
kGcTypeSticky | 使用粘性标记位(sticky mark bits)进行增量回收,仅释放自上次 GC 以来分配的对象。 | 高频轻量级 GC 场景(如后台 GC),减少暂停时间。适用于分配失败时的快速回收(如 kGcCauseForAlloc 触发)。 |
kGcTypePartial | 部分回收,仅标记和清理应用程序堆,不处理 Zygote 共享堆。 | 常规内存管理(如 kGcCauseBackground 触发),当 Zygote 堆无需回收时提升效率。避免共享内存的并发冲突。 |
kGcTypeFull | 完整回收,标记并清理应用程序堆和 Zygote 堆。 | 内存严重不足(如 OOM 风险)、显式 GC 调用(kGcCauseExplicit)或堆碎片整理时,释放最大内存。 |
kGcTypeMax | 表示 GC 类型的数量上限,非实际回收类型。 | 用于枚举或数组索引(如统计 GC 类型总数),不触发任何 GC 操作。 |
三、CollectorType(垃圾回收器类型):
# /art/runtime/gc/collector_type.h
28 enum CollectorType {
29 // No collector selected.
30 kCollectorTypeNone,
31 // Non concurrent mark-sweep.
32 kCollectorTypeMS,
33 // Concurrent mark-sweep.
34 kCollectorTypeCMS,
35 // Concurrent mark-compact.
36 kCollectorTypeCMC,
37 // The background compaction of the Concurrent mark-compact GC.
38 kCollectorTypeCMCBackground,
39 // Semi-space / mark-sweep hybrid, enables compaction.
40 kCollectorTypeSS,
41 // Heap trimming collector, doesn't do any actual collecting.
42 kCollectorTypeHeapTrim,
43 // A (mostly) concurrent copying collector.
44 kCollectorTypeCC,
45 // The background compaction of the concurrent copying collector.
46 kCollectorTypeCCBackground,
47 // Instrumentation critical section fake collector.
48 kCollectorTypeInstrumentation,
49 // Fake collector for adding or removing application image spaces.
50 kCollectorTypeAddRemoveAppImageSpace,
51 // Fake collector used to implement exclusion between GC and debugger.
52 kCollectorTypeDebugger,
53 // A homogeneous space compaction collector used in background transition
54 // when both foreground and background collector are CMS.
55 kCollectorTypeHomogeneousSpaceCompact,
56 // Class linker fake collector.
57 kCollectorTypeClassLinker,
58 // JIT Code cache fake collector.
59 kCollectorTypeJitCodeCache,
60 // Hprof fake collector.
61 kCollectorTypeHprof,
62 // Fake collector for installing/removing a system-weak holder.
63 kCollectorTypeAddRemoveSystemWeakHolder,
64 // Fake collector type for GetObjectsAllocated
65 kCollectorTypeGetObjectsAllocated,
66 // Fake collector type for ScopedGCCriticalSection
67 kCollectorTypeCriticalSection,
68 };
- 真实垃圾回收器(执行实际内存回收)类型
回收器类型 | 设计特点 | 应用场景 | 源码注释引用 |
---|---|---|---|
kCollectorTypeMS | 非并发标记-清除(Stop-the-world | 内存压力大时快速回收(如 kGcCauseForAlloc),阻塞应用线程 | [citation:31-32] |
kCollectorTypeCMS | 并发标记-清除(部分阶段与应用线程并发) | 减少停顿时间(如 kGcCauseBackground),适用于交互式应用 | [citation:33-34] |
kCollectorTypeCMC | 并发标记-整理(Concurrent Mark-Compact) | 兼顾低停顿与堆碎片整理(如大对象分配场景) | [citation:35-36] |
kCollectorTypeSS | 半空间复制 + 标记-清除混合(Semi-space/Mark-Sweep Hybrid) | 支持内存压缩(Compaction),解决堆碎片问题(如频繁分配释放后触发) | [citation:39-40] |
kCollectorTypeCC | 并发复制(Concurrent Copying) | 低延迟场景(如 kGcCauseHomogeneousSpaceCompact),减少暂停时间 | [citation:43-44] |
kCollectorTypeHomogeneousSpaceCompact | 同构空间压缩(专为 CMS 设计) | 当前后台回收器均为 CMS 时,后台整理堆碎片(kGcCauseHomogeneousSpaceCompact 触发) | [citation:53-55] |
- 后台回收器(辅助真实回收器)类型
回收器类型 | 协作对象 | 作用 | 源码注释引用 |
---|---|---|---|
kCollectorTypeCMCBackground | kCollectorTypeCMC | 执行 CMC 的后台压缩任务(与应用线程并发) | [citation:37-38] |
kCollectorTypeCCBackground | kCollectorTypeCC | 执行 CC 的后台复制任务(减少主回收器停顿时间) | [citation:45-46] |
- 虚拟回收器(仅用于同步,不执行回收)类型
回收器类型 | 保护目标 | 核心机制 | 源码注释引用 |
---|---|---|---|
kCollectorTypeHeapTrim | 堆内存修剪(kGcCauseTrim) | 释放未用物理内存页(不回收对象),避免与真实 GC 冲突 | [citation:41-42] |
kCollectorTypeInstrumentation | 代码性能分析工具 | 防止 GC 与插桩操作并发执行(如 Profiler) | [citation:47-48] |
kCollectorTypeAddRemoveAppImageSpace | App Image 空间管理 | 安全增删 App Image(避免与 GC 线程竞争) | [citation:49-50] |
kCollectorTypeDebugger | 调试器操作 | 防止断点/单步调试被 GC 中断 | [citation:51-52] |
kCollectorTypeClassLinker | 类加载器 | 保护 ART 方法元数据填充(如初始化特殊值) | [citation:56-57] |
kCollectorTypeJitCodeCache | JIT 代码缓存 | 防止 GC 与 JIT 编译元数据操作并发 | [citation:58-59] |
kCollectorTypeHprof | 堆转储(HPROF) | 避免堆转储与 GC 同时进行 | [citation:60-61] |
kCollectorTypeAddRemoveSystemWeakHolder | 系统弱引用持有者 | 安全增删全局弱引用(如 WeakReference 队列管理) | [citation:62-63] |
kCollectorTypeGetObjectsAllocated | 对象分配统计 | 防止统计过程被 GC 干扰 | [citation:64-65] |
kCollectorTypeCriticalSection | GC 临界区操作 | 实现线程安全(如 ScopedGCCriticalSection 作用域内禁止 GC) | [citation:66-67] |
四、垃圾回收(GC)过程概述:
真正负责垃圾回收逻辑的是下面这个方法:
# /art/runtime/gc/heap.cc
collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, // 垃圾回收的类型
GcCause gc_cause, // 触发 GC 的原因
bool clear_soft_references, // 是否清除软引用
uint32_t requested_gc_num) { // 请求的 GC 序列号(用于避免重复触发)
// --- 步骤 1: 初始化与线程状态管理 ---
Thread* self = Thread::Current(); // 获取当前线程
Runtime* runtime = Runtime::Current(); // 获取运行时环境
ScopedThreadStateChange tsc(self, ThreadState::kWaitingPerformingGc); // 切换线程状态为 GC 等待
Locks::mutator_lock_->AssertNotHeld(self); // 确保未持有 Mutator 锁(防死锁)
// --- 步骤 2: GC 可行性检查 ---
// 检查部分 GC 是否可执行(需 Zygote 空间支持)
switch (gc_type) {
case collector::kGcTypePartial:
if (!HasZygoteSpace()) {
return collector::kGcTypeNone; // 无 Zygote 空间则跳过
}
break;
default: break; // 其他 GC 类型无需特殊检查
}
// 栈溢出时跳过 GC(避免栈空间不足)避免递归崩溃
if (self->IsHandlingStackOverflow()) {
gcs_completed_.fetch_add(1); // 计数但不执行 GC
return collector::kGcTypeNone;
}
// --- 步骤 3: GC 同步与并发控制 ---
{
ScopedThreadStateChange tsc2(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_); // 获取 GC 完成锁
WaitForGcToCompleteLocked(gc_cause, self); // 等待正在进行的 GC 完成
// 检查 GC 请求是否已被其他线程处理
if (requested_gc_num != GC_NUM_ANY && !GCNumberLt(GetCurrentGcNum(), requested_gc_num)) {
return collector::kGcTypeNone; // 避免重复触发
}
// 检查移动式 GC 是否被禁用(如 JNI 临界区占用)
bool compacting_gc = IsMovingGc(collector_type_);
if (compacting_gc && disable_moving_gc_count_ != 0) {
gcs_completed_.fetch_add(1); // 计数但不执行
return collector::kGcTypeNone;
}
// 记录当前 GC 状态
collector_type_running_ = collector_type_; // 设置运行中的回收器类型
last_gc_cause_ = gc_cause; // 记录触发原因
}
// --- 步骤 4: 回收器选择 ---
collector::GarbageCollector* collector = nullptr;
bool compacting_gc = IsMovingGc(collector_type_);
if (compacting_gc) {
// 根据回收器类型选择具体实现
switch (collector_type_) {
case kCollectorTypeSS: // Semi-Space 回收器
semi_space_collector_->SetFromSpace(bump_pointer_space_);
semi_space_collector_->SetToSpace(temp_space_);
semi_space_collector_->SetSwapSemiSpaces(true);
collector = semi_space_collector_; // 配置半空间交换
break;
case kCollectorTypeCMC: // 并发标记整理
collector = mark_compact_; // 直接使用标记整理回收器
break;
case kCollectorTypeCC: // 并发复制
if (use_generational_cc_) {
// 分代模式:根据 GC 类型选择年轻代/老年代回收器
collector = (gc_type == collector::kGcTypeSticky) ?
young_concurrent_copying_collector_ :
concurrent_copying_collector_;
} else {
collector = active_concurrent_copying_collector_.load();
}
break;
default: LOG(FATAL) << "Invalid collector type";
}
} else if (current_allocator_ == kAllocatorTypeRosAlloc ||
current_allocator_ == kAllocatorTypeDlMalloc) {
collector = FindCollectorByGcType(gc_type); // 根据 GC 类型选择非移动式回收器(如 CMS)
}
// --- 步骤 5: 执行垃圾回收 ---
size_t bytes_allocated_before_gc = GetBytesAllocated();
collector->Run(gc_cause, clear_soft_references || runtime->IsZygote()); // 核心回收逻辑
// --- 步骤 6: 回收后处理 ---
IncrementFreedEver(); // 更新释放对象统计
RequestTrim(self); // 请求堆裁剪(异步)
SelfDeletingTask* clear = reference_processor_->CollectClearedReferences(self); // 处理被清除的引用
GrowForUtilization(collector, bytes_allocated_before_gc); // 根据利用率调整堆大小
LogGC(gc_cause, collector); // 记录 GC 日志
FinishGC(self, gc_type); // 清理 GC 状态(唤醒等待线程)
// --- 步骤 7: 资源清理 ---
clear->Run(self); // 实际处理引用队列(避免死锁)
clear->Finalize(); // 清理任务对象
Dbg::GcDidFinish(); // 通知 DDMS 调试器
// 卸载 Native 库(类卸载后执行,避免 JNI 死锁)
ScopedObjectAccess soa(self);
soa.Vm()->UnloadNativeLibraries(); //
return gc_type; // 返回实际执行的 GC 类型
}
由以上步骤 4
可以看出,通过gc_type
和collector_type_
决定去选择哪种回收器去执行垃圾回收工作,ART虚拟机中内置了多个垃圾回收器,继承关系如下:
GarbageCollector (基类)
│
├── MarkSweep (标记-清除回收器) // Full + CMS/MS
│ └── PartialMarkSweep (仅处理Image Space和Zygote Space之外的堆) // Partial + CMS/MS
│ └── StickyMarkSweep (仅处理上次GC之后创建的对象) // Sticky + CMS/MS
│
├── MarkCompact (标记-压缩回收器) // Full + CMC
│
├── ConcurrentCopying (并发复制回收器) // Partial/Sticky + CMC
│
└── SemiSpace (半空间复制回收器) // Partial + SS
└── ZygoteCompactingCollector (Zygote压缩收集器)
那么默认的collector_type_是多少呢,追踪所传的值为heap_ = new gc::Heap()
时传入的gUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_
不管是使用哪种收集算法,都有这四个步骤去处理收集工作:
83 void InitializePhase() ;
85 void MarkingPhase() ;
89 void ReclaimPhase() ;
90 void FinishPhase() ,
CC详细过程可查看:zhuanlan.zhihu.com/p/89536376
1. MarkSweep(标记-清除回收器)
-
工作流程:
- 标记阶段(Mark):从GC根对象(如线程栈、静态变量等)开始,递归遍历所有可达对象,并标记为存活。
- 清除阶段(Sweep):遍历除Image Space之外整个堆,回收未被标记的对象(垃圾)所占用的内存,并将其加入空闲列表。
2. PartialMarkSweep(部分标记-清除回收器)
-
工作流程:
- 只标记和清除Image Space和Zygote Space之外的内存区域。
- 标记和清除算法与
MarkSweep
相同。
3. StickyMarkSweep(粘性标记-清除回收器)
-
工作流程:
- 只标记和清除自上次垃圾回收以来新分配的对象
- 标记和清除算法与
MarkSweep
相同。
4. MarkCompact(标记-压缩回收器)
- 工作流程:
- 标记阶段:同 MarkSweep,标记所有存活对象。
- 压缩阶段:将存活对象向堆的一端移动,消除碎片,空闲空间连续。
- 更新引用:对象移动后,需遍历并修正所有对象引用地址。
5. ConcurrentCopying(并发复制回收器)
-
工作流程:
- 初始标记:从GC根对象(如线程栈、静态变量等)开始,递归遍历所有可达对象,标出不可达对象(垃圾对象),确定需要进行GC的
region
,经过分析,垃圾对象较多的区域会被搬移, 而垃圾对象较少的区域不会被搬移,原因这个区域大部分对象后面还会用到,copy操作是有成本的。这些被选中的region被称为source region
。 - 并发复制:系统将可达对象从 source region 复制到 destination region,并且确保在GC完成后没有任何指向 source region 内存的引用,然后修改所有指向 source region 的活对象使他们指向新的 destination region 中的新地址。此时如果有线程访问曾经存在于 source region 中的对象,GC的
read barrier
逻辑会截获这个读取并将数据拷贝到 destination region 然后返回拷贝到 destination region 的新引用地址,确保数据的一致性。 - 清理节阶段:此时整个进程中已不存在指向 source regions 的引用,GC将回收释放 source region 内存。
- 初始标记:从GC根对象(如线程栈、静态变量等)开始,递归遍历所有可达对象,标出不可达对象(垃圾对象),确定需要进行GC的
6. SemiSpace(半空间复制回收器)
-
工作流程(经典复制算法):
- 空间划分:堆分为两个等大的 "From" 和 "To" 半空间。
- 复制存活对象:GC 时,将 "From" 空间的存活对象复制到 "To" 空间。
- 空间交换:复制完成后,"To" 空间成为新 "From" 空间,原 "From" 空间清空。
变种:ZygoteCompactingCollector
-
特殊优化:
- 在 Zygote 进程分叉前,对半空间执行压缩(滑动对象消除碎片)。
- 确保子进程继承的堆内存紧凑,减少复制开销。