#はじめに
UE4はガベージコレクション(GC)機能を有しており定期的に使われていないオブジェクト(メモリ)を検索し解放しています。
バージョンを経るごとに改善が施され、最近の実装は時分割されてGCが行われ非常に高速になっています。ですが大規模なプロジェクトになるとオブジェクトの数の増加に伴い大きな負荷となり、処理落ちなどの原因になりえます。
そのGCの負荷を抑える仕組みの一つとしてGCClusterという機能があります。
大雑把にいうとアセットをロードしたときの芋ずる式にロードされたオブジェクトをGCに対してひとまとめにする機能です。
この機能はデフォルトで有効で、クックされた(パッケージを作成した)ビルドでのみこの機能が動作します。
このGCClusterを上手に調整してGCパフォーマンスを改善した事例がFF7REMAKEチーム様のプレゼンテーションで解説されておりますで、合わせてご参照いただけるとよろしいかと思います。
#GCClusterが問題になるケース
通常GCClusterは問題無く動作しGCの効率を高めてくれますが、あるオブジェクトが複数のGCRootから共有されていてさらに読み込み順序の兼ね合いによって本来あるべきではないクラスタを形成したり、ハードリファレンスが想定外のつながりを持ってしまっている場合に、GCClusterRootを開放したつもりなのにその子要素が解放されずに残ってしまう。といった問題が発生することがあります。
基本的には参照関係などを整理するなどの対処で正しくクラスタが生成されるように調整するのがもっとも望ましいのですが、構造上そのような対処が難しい場合は各オブジェクト毎にクラスターのルートになりえるかどうかを返す、UObjectBaseUtility::CanBeClusterRoot() やクラスターに含まれても良いかどうかを返す UObjectBaseUtility::CanBeInCluster() を利用して調整を行うことになります。
がまず最初に問題点を調査して構造を把握する必要があります。その方法について解説させていただきます。
#原因の調査方法
まずはGCClusterが本当に原因になっているかを調べるためにGCClusterを一時的に無効化し問題に変化があるかを調べてみてください。
プロジェクト設定から設定が可能です。
これで問題が改善するようであればGCClusterが悪影響を及ぼしています。
##オブジェクトの参照関係の確認 (obj refs)
もしメモリに残っているオブジェクトがわかっているのであれば、まず obj refs コマンドをつかって参照を調べるのをお勧めします。
コンソールコマンド記述例
obj refs Name=/Game/Mannequin/Character/Textures/T_UE4Logo_Mask.T_UE4Logo_Mask
実行すると以下の様な形で情報がログに出力されます。
(ClusterRoot)や(Clustered)といった出力に注目してください。
LogReferenceChain: (root) (standalone) World /Game/ThirdPersonBP/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap->PersistentLevel
LogReferenceChain: Level /Game/ThirdPersonBP/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap:PersistentLevel::AddReferencedObjects(): PersistentLevel
LogReferenceChain: ThirdPersonCharacter_C /Game/ThirdPersonBP/Maps/ThirdPersonExampleMap.ThirdPersonExampleMap:PersistentLevel.ThirdPersonCharacter_167->Class
LogReferenceChain: BlueprintGeneratedClass /Game/ThirdPersonBP/Blueprints/ThirdPersonCharacter.ThirdPersonCharacter_C::AddReferencedObjects(): ThirdPersonCharacter_C
LogReferenceChain: ThirdPersonCharacter_C /Game/ThirdPersonBP/Blueprints/ThirdPersonCharacter.Default__ThirdPersonCharacter_C::AddReferencedObjects()
LogReferenceChain: SkeletalMeshComponent /Game/ThirdPersonBP/Blueprints/ThirdPersonCharacter.Default__ThirdPersonCharacter_C:CharacterMesh0->SkeletalMesh
LogReferenceChain: (standalone) SkeletalMesh /Game/Mannequin/Character/Mesh/SK_Mannequin.SK_Mannequin->MaterialInterface
LogReferenceChain: (standalone) (ClusterRoot) Material /Game/Mannequin/Character/Materials/M_Male_Body.M_Male_Body->ReferencedTextures
LogReferenceChain: (standalone) (Clustered) Texture2D /Game/Mannequin/Character/Textures/T_UE4Logo_Mask.T_UE4Logo_Mask
このように正常なリファレンスが出力されているなら問題ないのですが、(Clustered)のオブジェクトだけが浮いている状態になってしまった場合に十分な情報が得られない場合があります。この場合はgc.ListClustersを使います。
##GC.ListClusters (引数無し)
引数無しで起動した場合、現状メモリ上にあるクラスタールートのリストを出力します。
> GC.ListClusters
Material /Game/Mannequin/Character/Materials/M_Male_Body.M_Male_Body (Index: 15556), Size: 29, ReferencedClusters: 0
Material /Engine/EngineSky/M_Sky_Panning_Clouds2.M_Sky_Panning_Clouds2 (Index: 15429), Size: 7, ReferencedClusters: 0
ParticleSystem /Engine/Tutorial/SubEditors/TutorialAssets/TutorialParticleSystem.TutorialParticleSystem (Index: 15739), Size: 23, ReferencedClusters: 0
Displayed 3 clusters
Total number of clusters: 3
Maximum cluster size: 29
Average cluster size: 19
Number of objects in GC clusters: 59
Maximum number of custer-to-cluster references: 0
Average number of custer-to-cluster references: 0
##GC.ListClusters Hierarchy
Hierarchyオプションを追加してコマンドを入力するとすべてのクラスタールートとその下にぶら下がっているオブジェクトも出力します。
> GC.ListClusters Hierarchy
Material /Game/Mannequin/Character/Materials/M_Male_Body.M_Male_Body (Index: 15556), Size: 29, ReferencedClusters: 0
[0000]: Package /Game/Mannequin/Character/Materials/M_Male_Body (Index: 15359)
[0001]: Package /Game/Mannequin/Character/Textures/T_UE4Logo_Mask (Index: 15460)
[0002]: Package /Game/Mannequin/Character/Textures/T_Male_N (Index: 15461)
[0003]: Package /Game/Mannequin/Character/Textures/T_Male_Mask (Index: 15462)
略
Material /Engine/EngineSky/M_Sky_Panning_Clouds2.M_Sky_Panning_Clouds2 (Index: 15429), Size: 7, ReferencedClusters: 0
[0000]: Package /Engine/EngineSky/M_Sky_Panning_Clouds2 (Index: 15317)
[0001]: Package /Engine/EngineSky/T_Sky_Blue (Index: 15318)
[0002]: Package /Engine/EngineSky/T_Sky_Clouds_M (Index: 15319)
略
ParticleSystem /Engine/Tutorial/SubEditors/TutorialAssets/TutorialParticleSystem.TutorialParticleSystem (Index: 15739), Size: 23, ReferencedClusters: 0
[0000]: Package /Engine/Tutorial/SubEditors/TutorialAssets/TutorialParticleSystem (Index: 15701)
[0001]: Package /Engine/Tutorial/SubEditors/TutorialAssets/M_smoke_subUV_blackbody (Index: 15707)
[0002]: Package /Engine/Tutorial/SubEditors/TutorialAssets/T_soft_smoke (Index: 15708)
略
##GC.ListClusters With=[オブジェクト名] Hierarchy
オブジェクト名がわかっている場合、With=オプションにその名前をふくめることで属するクラスタだけをログに出力することができます。
> gc.ListClusters With=/Game/Mannequin/Character/Textures/T_Male_N.T_Male_N Hierarchy
Material /Game/Mannequin/Character/Materials/M_Male_Body.M_Male_Body (Index: 15556), Size: 29, ReferencedClusters: 0
[0000]: Package /Game/Mannequin/Character/Materials/M_Male_Body (Index: 15359)
[0001]: Package /Game/Mannequin/Character/Textures/T_UE4Logo_Mask (Index: 15460)
...
[0023]: Texture2D /Game/Mannequin/Character/Textures/T_Male_N.T_Male_N (Index: 15550)
[0024]: Texture2D /Game/Mannequin/Character/Textures/T_Male_Mask.T_Male_Mask (Index: 15551)
[0025]: Texture2D /Game/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_N.T_ML_Rubber_Blue_01_N (Index: 15552)
[0026]: Texture2D /Game/Mannequin/Character/Materials/MaterialLayers/T_ML_Rubber_Blue_01_D.T_ML_Rubber_Blue_01_D (Index: 15553)
[0027]: Texture2D /Game/Mannequin/Character/Materials/MaterialLayers/T_ML_Aluminum01_N.T_ML_Aluminum01_N (Index: 15554)
[0028]: Texture2D /Game/Mannequin/Character/Textures/T_UE4Logo_Mask.T_UE4Logo_Mask (Index: 15555)
Referenced clusters: 0
External (mutable) objects: 0
Displayed 1 clusters
Total number of clusters: 3
Maximum cluster size: 29
Average cluster size: 19
Number of objects in GC clusters: 59
Maximum number of custer-to-cluster references: 0
Average number of custer-to-cluster references: 0
#リファレンス
UObjectClusters.cpp の ListClusters() を参照してください。