UE4反射和垃圾回收

本文介绍了UE4中的反射机制,包括宏的使用、类型层次及其实现机制,并通过实例展示了如何在代码中应用反射。此外,还详细解析了UE4的垃圾回收机制,包括其特性、对象的根集概念及其在Actor中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01 反射

什么是反射

反射是程序在运行时检查自身,将参与反射的数据(变量,类,函数等等)暴露给蓝图,允许运行时去调用。

反射的使用

宏就是用来帮助建立反射的,Unreal Header Tool(UHT)是建立反射的工具,它会扫描头文件。

例如:UE4中只要在一个函数的前面加上UFUNCTION()宏,然后在括号里面加上BlueprintCallable就可以在编辑器里面调用。

  • 为了标记一个头文件包含反射类型,需要添加一个头文件"XXX.generate.h"必须放在头文件的尾部,该文件一般位于“Project\工程名\Intermediate\Build\Win64\ Inc\工程名\类名.generate.h”

    #include "XXX.generate.h"
    
  • 可以使用UENUM()、UCLASS()、USTRUCT()、UFUNCTION()、以及UPROPERTY()来在头文件中注解不同的类型以及成员变量。每一个宏都会出现在类型或者成员变量的前面,并且可以包含额外的修饰符关键字。

    UCLASS() //标识类参与反射
    
    UPROPERTY()//标识属性参与反射
    
    UFUNCTION()//标识函数参与反射
    
    GENERATED_CODE//反射后的结果放置位置
    
  • UHT对代码文件内容进行处理,生成 .generated.h/.gen.cpp 文件,在生成的代码中加入反射信息。头文件中包一些函数实现声明的补全,对Current FileId的赋值,将一些函数注册到蓝图的虚拟中的操作。cpp文件(全局唯一)中会生成一个静态全局变量,在静态全局变量的构造函数中进行信息的注册,并将结果保存在UClass对象中(存放真实信息)。

反射的类型层次
img

UStruct是所有 聚合结构体的基础类型(包含其它成员的类型,比如一个C++类、结构体、或者函数),不应该跟C++中的结构体(struct)混为一谈(那是UScriptStruct)。UClass可以包含函数、属性以及它们的孩子,而UFunctionUStriptStruct只能包含属性。

img
反射实现机制

Unreal Build Tool(UBT)Unreal Header Tool (UHT)两个协同工作来生成运行时反射需要的数据。UBT属性通过扫描头文件,记录任何至少有一个反射类型的头文件的模块。如果其中任意一个头文件从上一次编译起发生了变化,那么 UHT就会被调用来利用和更新反射数据。UHT分析头文件,创建一系列反射数据,并且生成包含反射数据的C++代码(放到每一个模块的moulde.generated.inl中。注:最新版会生成到moudle.generated.cpp中),还有各种帮助函数以及thunk函数(每一个 头文件.generated.h

用生成的C++代码来存储反射数据的一个最大好处就是,它可以保证跟二进制做到同步。你永远也不会加载陈旧或者过时的反射数据,因为它是跟引擎的其它代码同时编译的,并且它会在程序启动的时候使用C++表达式来计算成员偏移等,而不是通过针对特定平台/编译器/优化的组合中进行逆向工程。

生成的诸如StaticClass()、StaticStruct()函数是为了让当前类型更好的获取反射数据,以及那此转换函数(thunks)用来在蓝图或者网络复制中调用C++函数。这些必须声明为类或者结构体的一部分,这也就解释了为什么GENERATED_UCLASS_BODY() or GENERATED_USTRUCT_BODY()宏会包含在你的反射系统的类型中,而#include "TypeName.generated.h"的头文件中定义了这些宏。

反射实例
#include "MyObject.generated.h"//虚幻引擎将生成所有反射数据并将放入此文件
 
UCLASS(Blueprintable)//Blueprintable:此类可由蓝图延展
class UMyObject : public UObject
{
    GENERATED_BODY()
 
public:
    MyUObject();
 
    UPROPERTY(BlueprintReadOnly, EditAnywhere)//BlueprintReadOnly:此属性只可从蓝图读取,不可写入
    float ExampleProperty;//EditAnywhere:说明此属性可通过属性窗口在原型和实例上进行编辑
 
    UFUNCTION(BlueprintCallable)//BlueprintCallable:公开属性在蓝图代码中调用
    void ExampleFunction();
};

02 垃圾回收机制(GC)

UE4中的GC是追踪式、非实时、精确式,非渐近、增量回收(时间片),先标记后回收的过程,为了提高效率和减少回收过程中的卡顿,可以做到并行标记和增量回收以及通过簇来提高回收的效率等。详解链接

UObject和垃圾回收

UE4的垃圾收集比较自动化,通过垃圾回收便无需手动删除 UObjects,只需维持对它们的有效引用即可。类须派生自 UObject,才能启用垃圾回收。

UCLASS()
class MyGCType : public UObject
{
    GENERATED_BODY()
};

在垃圾回收器中存在称为根集的概念,此根集是一个对象列表,回收器不会对这些对象进行垃圾回收。只要根集中的对象到讨论中的对象之间存在引用路径,对象便不会被垃圾回收。如对象到根集的此路径不存在,它便会被识别为无法达到,垃圾回收器下次运行时便会将其收集(删除),引擎以特定间隔运行垃圾回收器。

怎样才算是一个引用?存储在一个UPROPERTY属性中的UObject 对象指针。让我们看看简单的例子:

void CreateDoomedObject()
{
    MyGCType* DoomedObject = NewObject<MyGCType>();

当我们调用上面的方法时,我们实例化一个新的UObject对象,但我们没有存储对象指针到任何UPROPERTY的属性中,所以它不是根集的一部分。事实上,垃圾回收器会检测这个对象是否无法访问,若是,则回收它。

UE4采用了标记-清扫垃圾回收方式,是一种经典的垃圾回收方式。一次垃圾回收分为两个阶段。第一阶段从一个根集合出发,遍历所有可达对象,遍历完成后就能标记出可达对象和不可达对象了,这个阶段会在一帧内完成。第二阶段会渐进式的清理这些不可达对象,因为不可达的对象将永远不能被访问到,所以可以分帧清理它们,避免一下子清理很多UObject,比如map卸载时,发生明显的卡顿。

Actor和垃圾回收

Actors 通常不会被垃圾回收。Actors 生成后,必须手动调用 Destroy()。它们不会被立即删除,而会在下个垃圾回收阶段被清理。

UCLASS()
class AMyActor : public AActor
{
    GENERATED_BODY()
 
public:
    UPROPERTY()
    MyGCType* SafeObject;
 
    MyGCType* DoomedObject;
 
    AMyActor(const FObjectInitializer& ObjectInitializer)
        :Super(ObjectInitializer)
    {
        SafeObject = NewObject<MyGCType>();
        DoomedObject = NewObject<MyGCType>();
    }
};
 
void SpawnMyActor(UWorld* World, FVector Location, FRotator Rotation)
{
    World->SpawnActor<AMyActor>(Location, Rotation);
}

调用上述函数时,将在世界场景中生成一个actorActor的构建函数创建两个对象。一个指定到 UPROPERTY,另一个指定到裸指针。Actors自动成为根集的一部分,SafeObject将不会被垃圾回收,因为它从根集对象出到达。然而 DoomedObject的进展不是十分顺利。我们未将其标为UPROPERTY,因此回收器并不知道其正在被引用,而会将它逐渐销毁。

<think>我们正在处理用户关于UE4中"hood"报错的问题。据引用[1],UE4使用反射系统实现垃圾回收机制,要求类必须派生自UObject才能启用垃圾回收。这可能与对象生命周期管理有关。 用户提到的"hood"报错可能是特定于某个项目或插件的错误,但核心可能涉及UE4的对象管理机制。常见的UE4报错原因包括: 1. 未正确继承UObject导致垃圾回收问题 2. 对象引用失效(如被垃圾回收后仍尝试访问) 3. 资源加载失败(如模型、材质缺失) 解决方案建议: 1. 检查报错对象是否继承自UObject(或UStruct)并正确标记UPROPERTY() 2. 使用UE4的内存分析工具检查引用有效性 3. 验证相关资源是否存在 由于问题描述有限,以下提供通用排查步骤: 步骤1:查看完整错误日志(Output Log或崩溃报告) 步骤2:确认错误发生时操作(如加载场景、销毁对象等) 步骤3:检查相关代码中对象创建引用方式 如果问题与资源相关: - 验证资源路径是否正确 - 检查资源是否成功导入项目 如果问题与蓝图相关: - 检查蓝图节点是否有效连接 - 确保变量引用的对象未被销毁 由于引用[2]涉及Windows执行问题,可能与平台兼容性无关,但可注意: - 确保使用兼容的Visual Studio版本编译 - 检查插件兼容性 若用户提供更具体错误信息(如错误代码或调用堆栈),可进一步分析。 生成相关问题: 1. 如何查看UE4的详细错误日志? 2. UE4中如何正确使用UPROPERTY()防止对象被垃圾回收? 3. UE4资源加载失败常见原因有哪些?</think>### UE4 "hood" 报错分析与解决方案 在UE4开发中,"hood"相关报错通常与**资源加载失败**或**对象引用失效**有关。以下是常见原因解决方案: #### 常见原因分析 1. **资源引用丢失** - 场景中的"Hood"模型/材质被移动、重命名或删除,导致引用断裂 - 蓝图引用了不存在的`/Game/Characters/Hood/Mesh`等资产路径 - *特征:日志出现`Failed to load /Game/.../Hood_SkeletalMesh`错误* 2. **垃圾回收问题** - Hood对象未正确继承`UObject`且缺少`UPROPERTY()`宏标记[^1] - 对象被提前垃圾回收,导致访问无效指针 - *特征:报错含`Accessed None`或`Garbage Collection`关键字* 3. **插件兼容性问题** - Hood相关插件(如角色模块)与当前引擎版本不兼容 - 第三方插件未编译或依赖项缺失 4. **平台特定问题** - Windows文件路径大小写敏感问题(如`Hood.obj` vs `hood.obj`) - 文件权限问题(参考引用[2]中的SMB重定向问题)[^2] #### 解决方案步骤 **1. 基础修复流程** ```mermaid graph TD A[检查日志] -->|定位错误行| B[验证资源路径] B --> C[修复引用/重新导入] C --> D[添加UPROPERTY标记] D --> E[清理并重新编译] ``` **2. 详细操作:** - **资源丢失修复** 1. 在内容浏览器搜索`hood` 2. 右键选择"修复重定向器" 3. 重新指定缺失资源路径 4. 使用引用查看器(Reference Viewer)检查依赖关系 - **垃圾回收问题修复** 在C++类声明中添加: ```cpp UPROPERTY() AHoodActor* MyHood; // 确保派生自UObject[^1] ``` - **平台问题处理** - 关闭项目路径的只读属性 - 禁用防病毒软件实时扫描(常见于文件访问冲突) **3. 高级排查工具** - 使用`Obj List Class=HoodActor`控制台命令检查对象实例 - 启用`LogGarbage`日志级别查看回收详情 - 运行`VerifyProject`命令检测资产完整性 #### 预防措施 1. 使用版本控制(Git/Perforce)避免资源丢失 2. 所有UObject引用必须添加`UPROPERTY()`宏[^1] 3. 插件开发遵循引擎版本兼容性矩阵 > ⚠️ 若报错含`Windows API failed`,需检查文件系统权限(参考引用[2]的SMB重定向问题)[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值