【ART 内存管理】垃圾回收方案

11 阅读13分钟

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,避免应用卡顿
kGcCauseForNativeAllocNative内存分配超过阈值(NativeAllocationGcWatermark)可能阻塞,取决于GC策略
kGcCauseCollectorTransitionGC策略切换(如从年轻代收集器切换到老年代收集器)确保堆状态适应新收集器
kGcCauseHomogeneousSpaceCompactCMS收集器下空间压缩(仅当前后台均使用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缓存数组优化启动内存
kGcCauseStartupART虚拟机启动期间初始化堆状态
kGcCauseExit应用退出时释放资源清理堆残留对象
  • 工具与诊断
枚举值触发场景说明
kGcCauseHprof生成HPROF堆转储文件前触发GC确保转储数据一致性
kGcCauseJitJIT编译器内存分配失败编译代码时触发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]
  • 后台回收器(辅助真实回收器)类型
回收器类型协作对象作用源码注释引用
kCollectorTypeCMCBackgroundkCollectorTypeCMC执行 CMC 的后台压缩任务(与应用线程并发)[citation:37-38]
kCollectorTypeCCBackgroundkCollectorTypeCC执行 CC 的后台复制任务(减少主回收器停顿时间)[citation:45-46]
  • 虚拟回收器(仅用于同步,不执行回收)类型
回收器类型保护目标核心机制源码注释引用
kCollectorTypeHeapTrim堆内存修剪(kGcCauseTrim)释放未用物理内存页(不回收对象),避免与真实 GC 冲突[citation:41-42]
kCollectorTypeInstrumentation代码性能分析工具防止 GC 与插桩操作并发执行(如 Profiler)[citation:47-48]
kCollectorTypeAddRemoveAppImageSpaceApp Image 空间管理安全增删 App Image(避免与 GC 线程竞争)[citation:49-50]
kCollectorTypeDebugger调试器操作防止断点/单步调试被 GC 中断[citation:51-52]
kCollectorTypeClassLinker类加载器保护 ART 方法元数据填充(如初始化特殊值)[citation:56-57]
kCollectorTypeJitCodeCacheJIT 代码缓存防止 GC 与 JIT 编译元数据操作并发[citation:58-59]
kCollectorTypeHprof堆转储(HPROF)避免堆转储与 GC 同时进行[citation:60-61]
kCollectorTypeAddRemoveSystemWeakHolder系统弱引用持有者安全增删全局弱引用(如 WeakReference 队列管理)[citation:62-63]
kCollectorTypeGetObjectsAllocated对象分配统计防止统计过程被 GC 干扰[citation:64-65]
kCollectorTypeCriticalSectionGC 临界区操作实现线程安全(如 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_typecollector_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 内存。
6. SemiSpace(半空间复制回收器)
  • 工作流程(经典复制算法):

    • 空间划分:堆分为两个等大的 "From" 和 "To" 半空间。
    • 复制存活对象:GC 时,将 "From" 空间的存活对象复制到 "To" 空间。
    • 空间交换:复制完成后,"To" 空间成为新 "From" 空间,原 "From" 空间清空。
变种:ZygoteCompactingCollector
  • 特殊优化

    • 在 Zygote 进程分叉前,对半空间执行压缩(滑动对象消除碎片)。
    • 确保子进程继承的堆内存紧凑,减少复制开销。