概要
UE4のオブジェクトは、UPROPERTYを付けたポインタ変数で参照していればGCの破棄対象にならないというのは有名な話だが、付けていないのにGCにより破棄されないこともあり、どのような挙動になっているのか気になった為、少し調べてみた。
検証はUE4.24で行った。
検証内容
1.NewObjectで生成したActorを、生ポインタ変数で参照する
AActor* ObjectPointer;
ObjectPointer = NewObject<AActor>();
2.NewObjectで生成したActorを、別のActorにアタッチする
AActor* ObjectPointer;
ObjectPointer = NewObject<AActor>();
ObjectPointer->AttachToActor(this, FAttachmentTransformRules::SnapToTargetIncludingScale);
3.NewObjectで生成したActorを、UProperty付きのポインタ変数で参照する
UPROPERTY()
AActor* ObjectPointer;
ObjectPointer = NewObject<AActor>();
4.SpawnActorで生成したActorを、生ポインタ変数で参照する
AActor* ObjectPointer;
ObjectPointer = GetWorld()->SpawnActorDeferred<AActor>(AActor::StaticClass(), GetTransform());
ObjectPointer->FinishSpawning(GetTransform());
検証結果
1.NewObjectで生成したActorを、生ポインタ変数で参照する
→指定秒数後、GCにより破棄された。
やはり、生ポインタ変数で参照するだけでは、GCにより破棄されてしまうようだ。
2.NewObjectで生成したActorを、別のActorにアタッチする
→指定秒数後、GCにより破棄された。
アタッチされたオブジェクトは破棄されないように作られていたりするのか、気になって調べてみたが、破棄されてしまった。
アタッチしたActorも、破棄されないポインタ変数で管理した方が良さそうだ。
3.NewObjectで生成したActorを、UProperty付きのポインタ変数で参照する
→参照元のActorが存在する限り、破棄されなかった。
4.SpawnActorで生成したActorを、生ポインタ変数で参照する
→紐付いているレベルが破棄されるまで、破棄されなかった。
結論
NewObjectで生成したActorに関しては、UProperty付きのポインタ変数で参照しなければ、GCにより破棄されてしまう。
UE4でよく使うSpawnActorに関しては少し例外で、この関数で生成したActorはレベルから参照されているので、GCにより破棄されることは無かった。
ただし、レベル遷移などのタイミングで、オブジェクトが破棄されるタイミングが順不同になることがあるので、レベル遷移などのタイミングでも参照する可能性があるポインタ変数には、UPropertyを付けておいた方が安心だと思われる。
おまけ
Componentもポインタ変数で管理したりするが、ComponentはGCにより破棄されることは無いようだった。