【转载】[UE4] 对象内存管理几种模式

1,523 阅读2分钟

原文链接:[UE4]对象内存管理几种模式

防止 GC 的办法

1. UPROPERTY() 用法(针对于 UObject 系列对象,不能使用 TSharedPtr)

URPOPERTY()
UObject* MyObj;

2. AddToRoot 和 RemoveFromRoot 用法(针对于在 FObject 中引用 UObject 指针对象)

// 必须成对出现

// 初始化函数
UMyObject* MyObj = NewObject<UMyObject>();
MyObj.AddToRoot();

// 析构函数
m_sInstance->RemoveFromRoot();
m_sInstance = nullptr;

3. FObject 系列(使用 TSharePtr 智能指针来管理)

TSharedPtr<FObject> ObjPtr = MakeSharable(new FObject())

4. 在 FObject 中只是临时使用 UObject 指针对象

TWeakPtr<Class UObject> uObj*;  //使用裸指针来保存 UObject 指针,不负责管理

5. FStreamableManager 用法

FSoftObjectPath AssetPath(TEXT("/Game/Mannequin/Animations/ThirdPersonWalk.ThirdPersonWalk"));
FStreamableManager& AssetLoader = UAssetManager::GetStreamableManager();
//hold object in memory.
TSharedPtr<FStreamableHandle> Handle = AssetLoader.RequestSyncLoad(AssetPath, true);
UObject* Obj = Handle->GetLoadedAsset();
//free memory of object.
Handle->ReleaseHandle();

6. FGCObjectScopeGuard 用法

{
    FGCObjectScopeGuard(UObject* GladOS = NewObject<...>(...));
    GladOS->SpawnCell();
    RunGC();
    GladOS->IsStillAlive();   // Object will not be removed by GC
}

7

7.1 TArray<>

TArray 保持引用如果有个 TArray 容器,则这个 TArray 需要用一个 UPROPERTY() 去保持容器的引用,然后里面的 UObject 就不需要再去 AddToRoot 去阻止被 GC 了。

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UCoolDownComponent")
TArray<UCoolDown*> mCDArr;

UCoolDown* cd = NewObject<UCoolDown>(_class);
cd->SetSkillId(_skillId);
mCDArr.Add(cd);

容器 clear 后,元素会自动被 GC

7.2 TMap<>

4.15 版本支持了蓝图 TMap 容器,也是可以通过 UPROPERTY() 去保持容器的引用,容器内的 UObject 就不需要再去 AddToRoot 去阻止被 GC 了

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyChar")
        TMap<int32, UBehavData*> mTestMap2;

UBehavData* bh = NewObject<UBehavData>(this, UBehavData::StaticClass());
bh->mId = 111;
mTestMap2.Add(111, bh);
bh = NewObject<UBehavData>(this, UBehavData::StaticClass());
bh->mId = 222;
mTestMap2.Add(222, bh);

8

8.1 Destroying Objects(主动想删除)

你可以使用以下代码销毁运行时创建的对象:

if(!MyObject) return; 
if(!MyObject->IsValidLowLevel()) return;
MyObject->ConditionalBeginDestroy(); // instantly clears UObject out of memory 
MyObject = nullptr; 

8.2 Destroying Actors

可以使用以下代码来销毁 AActor 扩展类

if(!TheCharacter) return; 
if(!TheCharacter->IsValidLowLevel()) return;
TheCharacter->Destroy(); 
TheCharacter->ConditionalBeginDestroy(); // essential extra step, in all my testing 

8.3 AActor GC 机制

virtual void PostActorCreated() override;                                //做初始化工作
virtual void BeginPlay() override;                                       //做初始化工作
virtual void BeginDestroy() override;                                    //引擎在 GC 的时候调用,并不是立即调用,一般不用
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; //做清理工作
virtual void Destroyed() override;                                       //用于释放成员,调用 Destroy();会立即调用

8.4 UActorComponent GC 机制

// Begin UActorComponent Interface.
virtual void BeginPlay() override;                                       //组件 RegisterComponent 注册的时候,且有 OwnerActor 才会立即调用,一般不用
virtual void BeginDestroy() override;                                    //引擎在 GC 的时候调用,并不是立即调用,一般不用
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; //立即调用,一般这里做清理工作(注册过才会调用),且 GC 时还会再调用一次,一般不用
virtual void OnComponentCreated() override;                              //组件 RegisterComponent 注册的时候立即调用,一般这里做初始化工作
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;   //立即调用,一般这里做清理工作(只要 DestroyComponent 就会调用)

9. 参考资料

补充

[UE4]对象内存常驻的四种方式

TSharedPtr 是不能其他方法放到一起的,TSharedPtr 只能用于管理普通 C++ 对象的内存,而不能用于管理 UObjectUObject 对象内存只能由 GC 系统管理,TSharedPtr 的引用计数原理不能与其兼容。

另外补充两个用于管理 UOjbect 内存的方法: TWeakObjPtr,这个是对 UObject 的弱引用,不能保护不被 GC,但是如果被 GC,会自动置null,防止悬挂; 另外一个是 FGCObject