UE5 深入之 UGarbageCollection

简介: 走马观花看过了数据相关的,接下来浏览一下高级功能,第一个高级功能 UGarbageCollection,顾名思义,UE 的垃圾回收

UGarbageCollection

UE 的垃圾回收系统,用来消除大部分的手动内存管理负担
UGarbageCollection 不是一个独立的类,是一套由引擎核心+UObject基础架构共同实现的分布式系统。要说翻阅其代码,它有一个垃圾回收驱动器用来驱动整套系统的正常运作,文件路径如下:

  • 头文件(接口定义)Engine/Source/Runtime/CoreUObject/Public/UObject/GarbageCollection.h
  • 算法实现 Engine/Source/Runtime/CoreUObject/Private/UObject/GarbageCollection.cpp

核心机制

  1. 自动根集管理
    • 核心原则:标记所有被 UPROPERTY() 引用的对象
    • 自动防护:保护玩家控制器、GameState 等核心对象
    • 覆盖率:处理 95%+ 的对象存活需求
graph TD
    UPROPERTY[UPROPERTY标记] --> 根集
    GameState[GameState等核心对象] --> 根集
    全局对象 --> 根集
    根集 -. 保护 .-> 可达对象
    不可达对象 --> GC回收
  1. 引用链追踪算法
    • 关键优势:自动处理嵌套对象引用关系
    • 性能优化:增量式扫描(每帧<5ms)
// 简化版追踪逻辑:
void MarkReachable(UObject* Obj) {
    if(!Obj || Obj->IsMarked()) return;
    
    Obj->Mark(); // 标记为存活
    for(UProperty* Prop : Obj->GetProperties()) {
        if(UObject** Ref = Prop->GetObjectRef()) {
            MarkReachable(*Ref); // 递归追踪
        }
    }
}
  1. 对象声明周期钩子
    • 覆盖 90% 的资源清理场景
    • 安全释放:非托管资源(文件句柄/网络连接)
virtual void BeginDestroy() {
    // 释放非托管资源(如D3D纹理)
    Super::BeginDestroy();
}

virtual bool IsReadyForFinishDestroy() {
    // 异步资源释放检查点
    return TextureLoadCounter==0;
}
  1. 弱引用系统
    • 解决痛点:80% 的悬挂指针风险
    • 推荐场景:UI引用/事件监听/跨系统通信
TWeakObjectPtr<AActor> SafeRef; // 不阻止GC
if(SafeRef.IsValid()) { 
    // 对象仍然存在
}

⚙️ 20% 关键配置 (控制80%行为)

方法/机制 适用场景 使用频率 代码示例
UPROPERTY() 所有对象引用保护 ★★★★★ UPROPERTY() AActor* MyActor;
MarkPendingKill() 立即断开引用并标记待回收 ★★★★★ Obj->MarkPendingKill();
TWeakObjectPtr<> 安全跨帧引用 ★★★★☆ TWeakObjectPtr<AActor> WeakRef;
AddToRoot()/RemoveFromRoot() 创建永久对象 ★★☆☆☆ Obj->AddToRoot();
FGCObject 抽象类 管理非UObject资源 ★★★☆☆ 继承并实现 AddReferencedObjects
ForceGarbageCollection() 调试时强制GC ★★☆☆☆ GEngine->ForceGarbageCollection();
GUObjectArray.DisregardForGC() 临时豁免GC ★☆☆☆☆ GUObjectArray.DisregardForGC(Obj);
IsValidLowLevel() 安全检测待回收对象 ★★★★☆ if(IsValidLowLevel()) {...}

配置使用原则

  1. 99% 的情况使用 UPROPERTY() 足以保护对象
  2. 需要手动断开引用时优先使用 MarkPendingKill()
  3. 跨系统通信必须使用 TWeakObjectPtr<>
  4. 除非特殊需求,否则避免使用 AddToRoot()

阅读记录

ENUM_CLASS_FLAGS 宏的核心作用是将标准枚举类 (enum class) 扩展为支持位运算的位掩码类型,使其能够像整数一样进行按位操作,同时保持类型安全和编译时检查

  • 与传统方案的对比
特性 普通 enum enum class ENUM_CLASS_FLAGS(enum class)
类型安全 ❌ 不安全 ✅ 安全 ✅ 安全
命名空间隔离 ❌ 全局污染 ✅ 隔离 ✅ 隔离
位操作支持 ✅ 需手动转换 ❌ 不支持 ✅ 自动支持
隐式整数转换 ✅ 危险允许 ❌ 严格限制 ✅ 安全转换
UE反射整合 ❌ 有限支持 ❌ 有限支持 ✅ 完全支持
编译器类型检查 ❌ 无 ✅ 语法级检查 ✅ 语法+语义检查
组合类型安全性 ❌ 可与其他enum混合 ✅ 强制类型匹配 ✅ 运算符强制类型匹配
IDE智能提示支持 ❌ 不完整 ✅ 完整 ✅ 完整(含运算符提示)
线程安全保证 ❌ 依赖具体实现 ❌ 依赖具体实现 ✅ 原子操作实现
内存空间占用 编译器依赖(通常4B) 显式控制(可1B) 显式控制(同enum class)

FName 全局字符串标识系统

  • 引擎级的名称字典存储
  • 轻量级哈希表:通过整数ID实现高速名称比较
  • 大小写不敏感处理Weapon == WEAPON == weapon
  • FName核心特征
特性 说明
内存占用 仅存储整数ID (固定4字节)
比较速度 O(1) 常数时间 (直接整数比较)
字符串内容 不可修改 (immutable)
内存管理 全局共享池 (相同字符串单实例)

FString 动态字符串

  • 全功能字符串容器:类似C++的std::string
  • 文本处理工具箱:包含100+字符串操作方法
  • 动态内存管理:运行时可自由修改内容
  • FString核心特征
特性 说明
内存占用 动态分配 (堆内存) + 小字符串优化(SSO)
比较速度 O(n) 线性时间 (逐字符比较)
字符串内容 可任意修改 (mutable)
内存管理 完整UTF-16支持

FText

主要目标是为了处理需要本地化的文本

  • 国际化支持引擎:自动处理多语言文本切换
  • 格式安全系统:防注入攻击的文本格式化
  • 文本内容抽象化:分离文本显示逻辑与具体内容
  • 核心特征
特性 说明
内存占用 智能指针 + 共享数据实例 (内存高效)
比较机制 基于Key的比较 (非文本内容比较)
内容特征 不可变 (immutable) + 线程安全
格式化保护 自动参数转义防止文本注入
自动刷新 语言切换时实时更新UI文本

FText vs FName vs FString

特性 FText FName FString
设计目的 国际化显示 标识符管理 字符串操作
内存管理 ✅ 共享实例 ✅ 全局池 ❌ 独立实例
线程安全 ✅ 安全 ✅ 安全 ❌ 需同步
可变性 🔒 不可变 🔒 不可变 🔧 可变
比较方式 Key值比较 整数比较 文本比较
格式化安全 ✅ 自动转义 ❌ 不支持 ❌ 不安全
多语言支持 ✅ 完整 ❌ 无 ❌ 无
文本处理能力 ⚠️ 受限 ❌ 无 ✅ 丰富
哈希计算 ✅ 预计算 ✅ 预计算 ❌ 运行时计算
标识符类型 本地化Key 唯一整数ID 原始字符串
内存开销 中等 超低(4字节) 中高
性能特征 初始化较慢/使用快 极快(整数比较) 中等(字符遍历)
典型用途 UI本地化文本 资源路径/标签 文件操作/拼接
引擎整合 Slate UI系统 UObject引用系统 工具类API
字符串池 ✅ 本地化池 ✅ 全局名称池 ❌ 无池化
序列化支持 ✅ 含语言上下文 ✅ 仅ID序列化 ✅ 原始文本
内容来源 本地化资源文件 代码/配置定义 任意来源
输入风险 ✅ 安全(自动转义) ❌ 无保护 ❌ 高危
字符集支持 ✅ 全Unicode ✅ 但转为大写 ✅ 全Unicode
运行时生成 ❌ 受限 ⚠️ 昂贵(更新池) ✅ 完全支持
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容