UE5 系统浏览之 GarbageCollection(GC 垃圾回收系统)

简介: 系统浏览第一站,GC,本文先梳理一个GC系统的浏览路径,基本分成5个核心阶段,并在文末提供了调试技巧与

📁 核心代码文件清单

Engine/Source/Runtime/CoreUObject/Public/UObject/
    ├── GarbageCollection.h          # GC策略定义
    ├── ObjectMacros.h               # `GENERATED_BODY()`的GC宏
    └── UObjectBase.h                # `UObject`生命周期函数

Engine/Source/Runtime/CoreUObject/Private/UObject/
    ├── GarbageCollection.cpp        # GC主逻辑 (90%代码)
    ├── UObjectGarbageCollection.cpp # 对象级回收实现
    └── AsyncPurge.cpp               # 异步清理线程

Engine/Source/Runtime/CoreUObject/Private/Serialization/
    └── ObjectWriter.cpp              # GC与序列化交互 (`FReferenceCollector`)

阶段1:GC核心机制与标记流程

  1. 模块入口
    • 模块:CoreUObject
    • 启动入口:声明在 UObjectGlobals.h→ CollectGarbage() ,定义在GarbageCollection.cpp->CollectGarbage(EObjectFlags KeepFlags, bool bPerformFullPurge)
    • 内部调用函数:UE::GC::CollectGarbageInternal(KeepFlags, bPerformFullPurge);
  2. 标记阶段(Marking)
    • 关键类:
      • FReachabilityAnalysisState::PerformReachabilityAnalysis()
      • FRealtimeGC → PerformReachabilityAnalysis()
    • 关键函数:
      • PerformReachabilityAnalysis(...) (可达性分析)
        • StartVerseGC() (UE 新推出的 Verse 编程语言,这里是做了对它的 GC 标记功能的支持)
        • StartReachabilityAnalysis(...)(开始分析)
          • BeginInitialReferenceCollection(...)(判断是否并行处理)
          • MarkObjectsAsUnreachable(...)(标记不可达到的标签)
            • FGCFlags::SwapReachableAndMaybeUnreachable()(翻转标记为)
          • MarkClusteredObjectsAsReachable(...)(按簇标记可达性)
          • MarkRootObjectAsReachable(...)(标记根节点的可达性)
  3. 文件路径:
    • Engine/Source/Runtime/CoreUObject/Public/UObject/GarbageCollection.h
    • Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp
    • Engine/Source/Runtime/CoreUObject/Public/UObject/UObjectArray.h

阶段2:内存回收与销毁流程

  1. 回收阶段(Sweeping)
    • 关键函数:
      • void FReachabilityAnalysisState::PerformReachabilityAnalysisAndConditionallyPurgeGarbage(bool bReachabilityUsingTimeLimit) 分析并回收的入口
      • UE::GC::PostCollectGarbageImpl<true>(ObjectKeepFlags); 真正回收操作的调用
      • UE::GC::GatherUnreachableObjects 搜集所有不可达对象
      • UnhashUnreachableObjects 解除对象的 hash 关联
      • IncrementalPurgeGarbage 实际的清理调用
        • IncrementalDestroyGarbage 销毁 Garbage (在 IncrementalPurgeGarbage 内部调用)
          • Object->ConditionalFinishDestroy(); 在 IncrementalDestroyGarbage 内部调用 UObject 的销毁函数,实现Object 的真正销毁
          • GUObjectPurge.DestroyObjects(bUseTimeLimit, TimeLimit, GCStartTime); 提供流程控制和系统管理

🔧 关键调试技巧

  1. 触发GC断点调试
    • 控制台命令:
    ForceGarbageCollection     // 强制触发完整GC
    Obj List -unreachable       // 打印不可达对象
    
    • 断点位置:
      • CollectGarbage()(回收入口)
      • IsValid(Object)(检测悬垂指针)
  2. 检测内存泄漏
    • 日志过滤:
    LogGarbage: Log      // 打印GC过程对象数
    LogUObjectHash: Log  // 跟踪对象哈希表
    
    • 工具:
      • 内存分析器:UnrealInsights → "Garbage Collection"轨道
  3. 常见崩溃场景分析
错误现象 根源代码 解决方法
“Attempted to access garbage!” UObject::IsValid() 失败 检查弱引用升级UObject*
“Already in pending kill” UObject::ConditionalBeginDestroy()被重复调用 清除无效定时器引用
“Missing CDO” 类默认对象(CDO)被GC回收 在构造函数中调用AddToRoot()

⚡ 终极验证项目

  1. 创建继承UObject的自定义类,验证:
    • 在BeginDestroy()中输出日志
    • 通过AddToRoot()使其常驻内存
  2. 模拟资源异步加载回收:
    • 用FStreamableManager加载资源后释放引用
    • 观察GC是否回收UAsset对象
  3. 制造循环引用:
    • 两个UObject相互持有TStrongObjectPtr
    • 用OBJ REFS命令检查引用环

阅读记录

FGCCSyncObject GC 系统特有的用于多线程同步的核心类工具,UE的GC 标记是并行的,这个类的作用就是确保多线程并行都完成,用于防止 GC 的误清除或这内存的损坏,他是单例,全局只有一个

  • 类的声明在 GCScopeLock.h
  • 类函数的定义在 GarbageCollection.cpp

FReachabilityAnalysisState GReachabilityState; 实际的 garbageCollect 是通过这个类的 CollectGarbage(KeepFlags, bPerformFullPurge);来执行的

CSV_CUSTOM_STAT UE 中用于自定义性能监控数据的核心宏之一,属于UE的 CSV 性能分析系统(Comma-Separated Values Profiler)

FMemory::Trim(); UE内存管理系统的核心函数之一,它的主要作用是主动释放引擎内部内存分配器保留的未使用内存,整理内存碎片,建议调用间隔大于 30s

FUObjectItem 这个结构体包含了 UObject 的可达性flag
EInternalObjectFlags 内部的物体标签enum,包含了可达性flag
GIsIncrementalReachabilityPending 标记增量可达性分析是否在进行中

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容