5
3

More than 3 years have passed since last update.

[UE4] DisregardGCの使い方について

Last updated at Posted at 2021-03-11

1. 導入

 UE4のオブジェクトサイクルは、必要な時にオブジェクトを作成し、必要が無くなったタイミングでガーベージコレクションシステムによって削除されます。ガーベージコレクションシステムは自動的にオブジェクト管理をする上で便利ですが、時にはオブジェクトを意図的に削除したくないようなケースもあります。そこで、本記事ではオブジェクトを常駐するための方法について示します。

 オブジェクトを常駐させることは、ロード時間の短縮やロードによるヒッチの回避に役立ちます。必要なリソースを先にロードしたり、再利用することによって、都度必要なロードの機会を削減します。オブジェクトを常駐するには”DisregardForGC”を使用します。

2. 詳細

 “DisregardForGC”は、指定したobjectをgarbage collectの対象から除外することによってオブジェクトを永続的に生かす仕組みです。以下のリンク先にあるスライドで詳細に説明しています。Resources のページの [UE4におけるLoadingとGCのProfilingと最適化手法]からスライドをダウンロードすることもできます。
https://www.unrealengine.com/ja/resources?lang=ja

以下のスライドと同じです。
https://www.slideshare.net/EpicGamesJapan/ue4loadinggcprofiling

 UE4のオブジェクトは、全オブジェクトを格納する配列(GUObjectArray)で一元管理されています。DisregardForGCは、この配列に格納するオブジェクトの一部を非GC領域に格納することによってGCの対象から除外します。

2021-03-10_12h43_40.png

 DisregardForGCの対象となるオブジェクトは、エンジンの起動開始直後からFUObjectArray::CloseDisregardForGC()が呼ばれるまでの期間にロードされたオブジェクトです。このタイミングは、エンジンの初期化フェーズであるFEngineLoop::PreInitで、エンジンが必要な全てのオブジェクトのロードが行われますが、プロジェクトで使用するオブジェクトもこのタイミングでロードすることによって、常駐オブジェクトの対象とすることが可能です。

3. 前提

DisregardForGCを有効にします。 (gc.MaxObjectsNotConsideredByGCを>0の値に設定).

4. 使用例

実際にDisregardForGCの対象とすることが可能なロードの定義方法についていくつか紹介します。

例1

以下はシューターゲームにおける例です。DefaultGame.iniで指定したファイルをPostInitProperties()のタイミングでロードすることも有効です。
以下の場合、T_ImageAのTexture2Dは永続オブジェクトとして破棄されることはありません。

ShooterGameInstance.h
virtual void PostInitProperties() override;

UPROPERTY(config)
TArray<FString> StartupPackages;
ShooterGameInstance.cpp
void UShooterGameInstance::PostInitProperties()
{
    Super::PostInitProperties();
    for (FString PackageName : StartupPackages)
    {
        LoadPackage(nullptr, *PackageName, 0);
    }
}
DefaultGame.ini
[/Script/ShooterGame.ShooterGameInstance]
+StartupPackages=/Game/Textures/T_ImageA

例2

別の例として、GameInstanceのコンストラクタでテクスチャをロードしていますが、これが呼ばれるタイミングはDisregardForGCがまだクローズしていないため、ここでロードされたTexture2D オブジェクトは最終的に永続オブジェクトとして破棄されません。​

ShooterGameInstance.cpp

UShooterGameInstance::UShooterGameInstance(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
    , OnlineMode(EOnlineMode::Online) // Default to online
    , bIsLicensed(true) // Default to licensed (should have been checked by OS on boot)
{
    UTexture2D* DisregardGCTexture = LoadObject<UTexture2D>(NULL, TEXT("/Game/Textures/T_ImageB.T_ImageB"), nullptr, LOAD_None, nullptr);
}

例3

さらに別の例として、UObjectから派生したクラスでPostCDOContructでアセットをロードする例です。

MyObject.cpp
void UMyObject::PostCDOContruct()
{
    UTexture2D* DisregardGCTexture = LoadObject<UTexture2D>(NULL, TEXT("/Game/Image/TextureC.TextureC"), nullptr, LOAD_None, nullptr);
}

5. QA

Q:どのオブジェクトでロードしたものが対象となる?
A:UObjectを継承したクラスが対象。非UObjectのクラスは対象外。

Q:どのモジュール(タイミング)でロードしたものが対象となる?
A:エンジンの初期化時に全UObjectのCDO(CreateDefaultObject)処理が走るため、そこに関連するConstructorPostInitProperties, PostCDOContructでロードしておけばDisregardForGCの対象となります。使用例を参照。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3