文章目录
一、UObject成员变量必须用 UPROPERTY 修饰
如果 UObject 类型的成员变量未被标记为 UPROPERTY,GC 将无法识别其引用,导致对象可能被错误回收。
// MyClass.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyClass.generated.h"
UCLASS()
class UMyClass : public UObject
{
GENERATED_BODY()
public:
// 未使用 UPROPERTY 修饰 → 可能被GC回收
UObject* UnreferencedObject;
// 使用 UPROPERTY 修饰 → GC会追踪引用
UPROPERTY()
TObjectPtr<UObject> ReferencedObject;
};
验证方式
- 若 UnreferencedObject 未被其他引用持有,其指向的对象可能在GC时被回收。
- ReferencedObject 会始终被GC追踪,只要 UMyClass 实例存活。
二、实现 AddReferencedObjects 接口
当需要手动管理非 UPROPERTY 成员变量或复杂引用关系时,可重写 AddReferencedObjects 方法。
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
public:
// 非 UPROPERTY 成员变量
UObject* OtherObject;
protected:
// 重写 AddReferencedObjects 手动添加引用
virtual void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector) override
{
Collector.AddReferencedObject(OtherObject);
Super::AddReferencedObjects(InThis, Collector);
}
};
关键点
- 即使 OtherObject 未被 UPROPERTY 修饰,通过 AddReferencedObjects 手动添加引用,GC 会将其标记为“被引用”。
- 适用于动态管理对象引用的场景(如对象池、缓存)。
三、结构体继承 FGCObject 并实现 AddReferencedObjects
如果结构体(struct)包含 UObject 指针且需要被GC保护,必须继承 FGCObject 并手动添加引用。
// MyStruct.h
#pragma once
#include "UObject/GCObject.h"
// 自定义结构体继承 FGCObject
class FMyStruct : public FGCObject
{
public:
// 结构体中持有 UObject 指针
UObject* MyObject;
// 必须重写 AddReferencedObjects
virtual void AddReferencedObjects(FReferenceCollector& Collector) override
{
Collector.AddReferencedObject(MyObject);
}
};
// 使用示例
void ExampleUsage()
{
FMyStruct MyStructInstance;
MyStructInstance.MyObject = NewObject<UObject>();
// 只要 MyStructInstance 存在,MyObject 不会被GC回收
}
关键点
- 适用场景:非 USTRUCT 的自定义原生结构体(如工具类、独立于UObject系统的模块)。
- 对比 USTRUCT:若结构体是 USTRUCT,且其成员用 UPROPERTY 标记,则无需继承 FGCObject,例如:
USTRUCT()
struct FMySafeStruct
{
GENERATED_BODY()
UPROPERTY()
TObjectPtr<UObject> SafeObject; // 自动被GC追踪
};
总结
场景 | 方法 | 代码示例 |
---|---|---|
UObject成员变量引用 | 使用 UPROPERTY 标记 | UPROPERTY() TObjectPtr Ref; |
手动管理复杂引用 | 重写 AddReferencedObjects | virtual void AddReferencedObjects(…) { Collector.AddRef(Obj); } |
结构体保护UObject引用 | 继承 FGCObject 并实现接口 | struct FMyStruct : FGCObject { … } |
注意事项:
- USTRUCT 的特殊性:
- 若结构体是 USTRUCT,其内部 UObject 指针必须用 UPROPERTY 修饰,否则无法自动追踪引用。
- 原生结构体(非 USTRUCT)必须通过 FGCObject 手动管理引用
- 性能影响:
- AddReferencedObjects 在GC时会被频繁调用,确保代码高效,避免复杂逻辑。
- 循环引用:
- 即使通过上述方法保护对象,若对象间形成循环引用(如A引用B,B引用A),需手动打破循环(如使用弱指针 TWeakObjectPtr)。