(UE4 4.20 )UE4的GC(垃圾回收)程式設計規範

小毛狗發表於2019-01-12

 

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 properties
	ATestActor();

	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<UCameraComponent>(TEXT("Camera"));
	cameraComponent->SetupAttachment(RootComponent);

}
UCLASS(config=Game)
class AMyProject3Character : public ACharacter
{
	GENERATED_BODY()

public:
    TWeakObjectPtr<UCameraComponent> cameraComponent;

protected:
    virtual void BeginPlay() override;
}



void AMyProject3Character::BeginPlay()
{
	Super::BeginPlay();
	TArray<AActor*> arrayActor;
	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATestActor::StaticClass(), arrayActor);
	if (arrayActor.Num() > 0)
	{
		ATestActor* testActor = Cast<ATestActor>(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<UTestObject>(this);

	testObject->AddToRoot();
	testObject->a = 1.0f;
	UE_LOG(LogTemp, Error, TEXT("xxxx = %f"), testObject->a);

	
	testObject->RemoveFromRoot();
}

 

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 properties
    ATestActor();


    TSharedPtr<FTest> Test;
protected:
    // Called when the game starts or when spawned
    virtual 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<FTest> Test;
	Test = MakeShareable(new FTest());

}

 

FGCObject

上面我們說到了UObject的情況,採用NewObject建立和UPROPERTY()標記來進行GC。而不繼承UObject的自定義結構體採用MakeShareable來建立,用TSharedPtr來管理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

 

相關文章