4
2

More than 1 year has passed since last update.

[UE4]GC Clusterによって開放されない問題について

Last updated at Posted at 2022-07-13

検証UE4: 4.27.2
まちがってたらごめんなさい。

まとめ

  • 別のClusterに同一アセットが入っていると開放できない。
    • 参照するアセットに注意。
    • 開放する順番にも注意。
  • Cluster Rootの対象を増やす際は注意。
    • エンジンデフォルトだとParticleSystem/Material等だけで問題が出にくい
    • 自前で増やす際は注意

参考

Cluster Rootの対象

デフォルトでCluster Rootになり得るのは、下記のみかと思います。(C++側のCanBeClusterRootを確認)
・Material
・ParticleSystem(Cascadeの方)

プロジェクト設定で下記もRoot化できます。
image.png
・BP
 → 「ブループリントクラスタリングが有効」(gc.BlueprintClusteringEnabled)

またC++では CanBeClusterRoot を override してRoot化するか指定できます。
image.png

開放されないCluster

image.png

検証

こんな構成の、パーティクルシステムが配置されたサブレベルが有ります。
Level[A] - ParticleSystem[A] - Material[A] - Texture[Green]
Level[B] - ParticleSystem[B] - Material[B] - Texture[Green]

このレベルをLevelStreamingで下記の順でロード操作します。
1)LevelA -> ロード
2)LevelB -> ロード
3)LevelA -> アンロード
4)LevelB -> アンロード

  • ロード前
    • Obj List: Class=ParticleSystem
      0 Objects
      
  • 1)LevelA -> ロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_A.PS_A
      
  • 2)LevelB -> ロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_A.PS_A
      ParticleSystem /Game/PS_B.PS_B
      
  • 3)LevelA -> アンロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_A.PS_A ←※
      ParticleSystem /Game/PS_B.PS_B
      
  • 4)LevelB -> アンロード
    • Obj List: Class=ParticleSystem
      0 Objects
      

(3)の「LevelA アンロード」の時点で"PS_A"は使用がなくなった筈ですが、開放されません。
(4)の「LevelB アンロード」されると開放されます。

問題

開放されないという事で、いつも通り誰が持ってるか調べようと参照元を辿る obj refs で見ると下記のように出てきます

obj refs Name=PS_A
LogReferenceChain: (standalone) (ClusterRoot) ParticleSystem /Game/PS_A.PS_A is not currently reachable.

調べようとしても誰が持ってるか分からない状態になっています。

この場合は、 gc.DumpRefsToCluster Root=<Root名> でCluster参照を出力できます。

gc.DumpRefsToCluster Root=PS_A
LogObj: Display: Dumping references to objects in cluster ParticleSystem /Game/PS_A.PS_A
LogReferenceChain: (root) (NeverGCed) GCObjectReferencer /Engine/Transient.GCObjectReferencer_2147482645::AddReferencedObjects(): FParticleSystemWorldManager
LogReferenceChain:  ParticleSystemComponent /Game/LV_SubB.LV_SubB:PersistentLevel.PS_B_2.ParticleSystemComponent0->Template
LogReferenceChain:   (standalone) (ClusterRoot) ParticleSystem /Game/PS_B.PS_B->Emitters
LogReferenceChain:    (Clustered) ParticleSpriteEmitter /Game/PS_B.PS_B:ParticleSpriteEmitter_0->LODLevels
LogReferenceChain:     (Clustered) ParticleLODLevel /Game/PS_B.PS_B:ParticleSpriteEmitter_0.ParticleLODLevel_0->RequiredModule
LogReferenceChain:      (Clustered) ParticleModuleRequired /Game/PS_B.PS_B:ParticleModuleRequired_0->Material
LogReferenceChain:       (standalone) (Clustered) Material /Game/M_ParticleB.M_ParticleB->TextureValues
LogReferenceChain:        (standalone) (Clustered) Texture2D /Engine/EngineResources/AICON-Green.AICON-Green->Outer
LogReferenceChain:         (Clustered) Package /Engine/EngineResources/AICON-Green

原因としては、 別々のClusterで同じアセットを参照している事が問題になります。

パーティクルシステムはClusterRootになるObjectです。
PS_A, PS_BはそれぞれClusterのRootになっています。

gc.ListClusters

LogObj: Display: ParticleSystem /Game/PS_A.PS_A (Index: 15945), Size: 15, ReferencedClusters: 0
LogObj: Display: ParticleSystem /Game/PS_B.PS_B (Index: 15970), Size: 13, ReferencedClusters: 1
LogObj: Display: Displayed 2 clusters
LogObj: Display: Total number of clusters: 2

image.png
PS_A, PS_Bの2つで使用しているテクスチャが同じアセットを使用しています。(上記赤枠)
ロード順で、該当テクスチャは先にロードされたPS_Aのクラスタに入っています。
その為、PS_Aを開放するにはテクスチャの開放が必要。
→ 参照先(PS_B)が開放されていないと、PS_Aは開放できません。

対策

  • Cluster Rootの対象を考慮する
    • エンジンのデフォルト的に今回はParticleSystemですが、
      前述の設定であるようにBPやC++で独自に対象にすると問題が色々出る事が考えられます。
  • 強制的に開放する
    該当の開放できない状態((3)のLevelAアンロードした状態)で、
    gc.CreateGCClusters 0
    
    を実行してClusterを開放。次にGCが走ると、開放できなかったPS_Aが開放されます。
    必要があれば再度 gc.CreateGCClusters 1 に戻すとか。

開放する順番について

アンロード順を変更して、Bを先に開放すると、問題なく開放されます。
PS_Bで使用する該当のテクスチャアセットが、PS_Aクラスタに入っている為
1)LevelA -> ロード
2)LevelB -> ロード
3)LevelB -> アンロード
4)LevelA -> アンロード

  • ロード前
    • Obj List: Class=ParticleSystem
      0 Objects
      
  • 1)LevelA -> ロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_A.PS_A
      
  • 2)LevelB -> ロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_A.PS_A
      ParticleSystem /Game/PS_B.PS_B
      
  • 3)LevelB -> アンロード
    • Obj List: Class=ParticleSystem
      ParticleSystem /Game/PS_B.PS_A
      
  • 4)LevelA -> アンロード
    • Obj List: Class=ParticleSystem
      0 Objects
      
4
2
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
4
2