热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(UE44.20)UE4的GC(垃圾回收)编程规范

UObject系统的GCUPROPERTY引用当我们在一个UObject类声明各种继承UObject的变量时,得加UPROPERTY(),这个可以让UE4帮我们自


UObject系统的GC


UPROPERTY 引用

当我们在一个UObject类声明各种继承UObject的 变量时,得加UPROPERTY(), 这个可以让UE4帮我们自动管理UObject的垃圾回收。UPROPERTY不仅仅用于反射变量到编辑器上编辑,也涉及UObject变量的GC。

如下面所示:

UCLASS(config=Game)
class AMyProject1Character : public ACharacter
{GENERATED_BODY()private:UPROPERTY()UObject* object;}

TWeakObjectPtr

UE4里自创一套C++ GC规则,官方并不推荐使用C++标准库。 学C++的同学可能会对弱指针熟悉,可以访问一个对象又不造成引用计数加1。通常定义在一个类内,用于获取其他对象的某个变量当成临时变量方便访问。如下面所示:

UCLASS()
class MYPROJECT3_API ATestActor : public AActor
{GENERATED_BODY()public: // Sets default values for this actor's propertiesATestActor();UPROPERTY(VisibleAnywhere)class UCameraComponent* cameraComponent;};ATestActor::ATestActor()
{// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;cameraComponent = CreateDefaultSubobject(TEXT("Camera"));cameraComponent->SetupAttachment(RootComponent);}

UCLASS(config=Game)
class AMyProject3Character : public ACharacter
{GENERATED_BODY()public:TWeakObjectPtr cameraComponent;protected:virtual void BeginPlay() override;
}void AMyProject3Character::BeginPlay()
{Super::BeginPlay();TArray arrayActor;UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATestActor::StaticClass(), arrayActor);if (arrayActor.Num() > 0){ATestActor* testActor = Cast(arrayActor[0]);if (nullptr == testActor)return;cameraComponent = testActor->cameraComponent;}
}

这里CameraComponent组件创建与Te'stActor,但是AMyproject2Character需要保存临时变量的时候就用弱指针保存。


局部创建的UObject对象GC

局部创建并且在局部使用的UObject要调用AddToRoot来防止被GC, 然后 RemoveFromRoot来移除引用能得到GC

UCLASS()
class MYPROJECT4_API UTestObject : public UObject
{GENERATED_BODY()public:UTestObject(){}float a;};void AMyProject4Character::BeginPlay()
{Super::BeginPlay();UTestObject* testObject = NewObject(this);testObject->AddToRoot();testObject->a = 1.0f;UE_LOG(LogTemp, Error, TEXT("xxxx = %f"), testObject->a);testObject->RemoveFromRoot();
}

普通结构体Struct的GC

不继承UObject和UStruct对象的结构体的GC有下面几条


TSharedPtr

共享智能指针,类似C++标准库的共享智能指针,不能用于UObject对象(TWeakPtr倒是可以用于UObject), 因为UObject有自己 专门GC的一套规则。总之TSharedPtr用于自定义的结构体(不继承UObject)。

如下所示:

class MYPROJECT2_API FTest
{
public:FTest();~FTest();
};#include "FTest.h"FTest::FTest()
{UE_LOG(LogTemp, Warning, TEXT("1111FTest Constrction"));
}FTest::~FTest()
{UE_LOG(LogTemp, Warning, TEXT("2222FTest Deconstrction"));
}

UCLASS()
class MYPROJECT2_API ATestActor : public AActor
{GENERATED_BODY()public:    // Sets default values for this actor's propertiesATestActor();TSharedPtr Test;
protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;}// Called when the game starts or when spawned
void ATestActor::BeginPlay()
{Super::BeginPlay();Test = MakeShareable(new FTest());}

PIE运行时Actor创建:

PIE取消运行Actor销毁:

如果是局部变量的结构体创建TSharedPtr:


void ATestActor::BeginPlay()
{Super::BeginPlay();TSharedPtr Test;Test = MakeShareable(new FTest());}


FGCObject

上面我们说到了UObject的情况,采用NewObject创建和UPROPERTY()标记来进行GC。而不继承UObject的自定义结构体采用MakeShareable来创建SharedPtr来管理GC。这时候一个特殊的情况出现了玩意,一个不继承UObject的结构体中出现UObject对象怎么办?如下面所示:

*/
UCLASS(BlueprintType, notplaceable, MinimalAPI)
class UCameraAnim : public UObject
{。。。。。。。。。。。。。。。。。。。。。。。。
}class UCameraAnim;
/*** */class MYPROJECT2_API FTest
{
public:FTest();~FTest();UPROPERTY()UCameraAnim* CameraAnim;
};

这种情况下,我试过,如果用MakeShareable创建结构体指针,然后直接操作结构体的UObject对象进行NewObjec创建,结构体本身的访问没问题,但是结构体里面的UObject对象一段时间后自动GC掉,成为野指针,不能访问。这种情况怎么解决呢?UE4为我们提供了FGCObject ,我们的结构体继承FGCObject ,然后用AddReferencedObjects 方法引用结构体里的所有UObject对象,这里的UObject对象不需要被UPROPERTY()标记, 如下所示

#include "GCObject.h"class UCameraAnim;
/*** */
class MYPROJECT2_API FTest :public FGCObject
{
public:FTest();~FTest();UCameraAnim* CameraAnim;protected:virtual void AddReferencedObjects(FReferenceCollector& Collector) override{Collector.AddReferencedObject(CameraAnim);}
};


TSharedRef

本质上共享引用(TSharedRef)和共享指针(TSharedPtr)是差不多的,一样是用于非UObject体系的对象,具备引用计数器,不过TSharedRef和TSharedPtr的很大不同在于,共享引用无法引用空对象,就像C++ 声明空引用,编译直接报错。TSharedRef连
“IsValid”判断是否非空都没有,强逼你使用必定是有效的引用。所以在UE4 的SWidget编程大量使用TSharedRef

如 int& a;

正确的声明定义

TSharedRef MyCustom = MakeShared();

错误的声明定义:

TSharedRef MyCustom;TSharedRef MyCustom = nullptr;

TSharedRef没有空引用,应该持有的对象必须是有效的

TSharedPtr转为TSharedRef

TSharedPtr aaa = MakeShareable(new FMyCustom);
TSharedRef a = aaa.ToSharedRef();

一个普通的结构体使用TSharedFromThis继承,就可以拥有AsShared函数让普通的结构体对象转为TSharedRef, 像SWidget这个类本身就使用了TSharedFromThis

struct FMyCustom : TSharedFromThis
{int a = 1;FMyCustom(){UE_LOG(LogTemp, Error, TEXT("destruct a = %d"), a);}~FMyCustom(){UE_LOG(LogTemp, Error, TEXT("undestruct a = %d"), a);}
};FMyCustom MyCustom;
RefCustom = MyCustom.AsShared();

TSharedRef可以转化为TSharedPtr, 直接等于就可以了

TSharedRef RefCustom = MakeShared();TSharedPtr PtrCustom = RefCustom;


TWeakPtr

上面我们说到了 TWeakObjectPtr 为专门用于UObject, 相应的普通结构体也有弱指针TWeakPtr, 能够访问一个非UObject对象,但是又不造成引用计数+1

一般来说通过TWeakPtr来访问其持有的对象,先是用pin转换为TSharePtr指针,判断对象是否有效后,再访问,而不是直接通过弱指针的IsValid,然后直接访问

struct FMyCustom
{int a = 1;FMyCustom(){UE_LOG(LogTemp, Error, TEXT("destruct a = %d"), a);}~FMyCustom(){UE_LOG(LogTemp, Error, TEXT("undestruct a = %d"), a);}
};UCLASS()
class MYPROJECT5_API AMyActor : public AActor
{
public:TWeakPtr WeakCustom;virtual void BeginPlay() override;virtual void Tick(float DeltaTime) override;}void AMyActor::BeginPlay()
{Super::BeginPlay();TSharedPtr ShareCustom = MakeShareable(new FMyCustom);WeakCustom = ShareCustom;}// Called every frame
void AMyActor::Tick(float DeltaTime)
{Super::Tick(DeltaTime);TSharedPtr ShareCustom = WeakCustom.Pin();if (ShareCustom.IsValid()){UE_LOG(LogTemp, Error, TEXT("a = %d"), ShareCustom->a);}}

很显然,弱指针没有引用到局部的智能创建的对象,所以没有“Tick a  = 1”的log


TSharedPtr,TSharedRef, TWeakPtr在容器使用事项

得注意:弱指针(TWeakPtr)对象不能作为Set或者Map的Key,因为一个对象被GC掉无法通知一个容器的Key, 像TMap, int>就是不正当的使用手法,当然TWeakPtr可以作为容器的Value,  TMap>毫无问题。

而TSharedPtr和TSharedRef既可以当作容器的Key,也可以作为容器的Value.


参考资料

[1] https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/SmartPointerLibrary/index.html


推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
author-avatar
原来我不帅S_420
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有