はじめに
こUnityのAddComponentの呼び出しの負荷が高いことは度々話題になります.
Unity AddComponent Very Inefficient and Slow (StackOverflow)
この記事では, AddComponentが重い件への1つの対処法について解説します.
概要
ざっくり結論としては,一度に大量のGameObjectを生成しAddComponentをするようなケース においてはAddComponentを呼び出す回数をなるべく減らすため, すでにAddComponentが行われたGameObjectをInstantiateするとよい というものです.
実行環境
実行時間などの参考に検証をした環境を明示しておきます.
- Ryzen 9 5900X
- Unity 2020.3.8f1
- Windows 10 64bit
- Performance testing API 2.8.0-preview
検証
今回の記事では,UnityのPerformance testing APIを使った簡単なベンチマークテストで以下の2パターンの速度について検証します.
- 100000回GameObjectを生成し,都度AddComponentした場合
- 1度AddComponentしたGameObjectをInstantiateで複製した場合
// GameObject生成 -> AddComponent
// x 10000
[Performance]
[Test]
public void AddComponentProfilingTest()
{
Measure.Method(() =>
{
for (int i = 0; i < 10000; i++)
{
var obj = new GameObject();
obj.AddComponent<EmptyComponent>();
}
})
.WarmupCount(1)
.IterationsPerMeasurement(1)
.MeasurementCount(20)
.Run();
}
// AddComponent -> Instantiate
// x 10000
[Performance]
[Test]
public void InstantiateProfilingTest()
{
Measure.Method(() =>
{
var template = new GameObject();
template.AddComponent<EmptyComponent>();
for (int i = 0; i < 10000 - 1; i++)
{
var obj = Object.Instantiate(template);
}
})
.WarmupCount(1)
.IterationsPerMeasurement(1)
.MeasurementCount(20)
.Run();
}
結果
測定した結果,
- 都度AddCompnent : 481.79ms (Median)
- Instantiateで複製 : 93.67ms (Median)
とおよそ5倍高速化される結果となりました.
実行環境によっては更に差が出ることもありそうに思えます.
AddCompnentはComponentの重複チェックなどの処理が行われるためオーバーヘッドが大きく,大量に行う場合はInstantiateで複製したほうが効率が良さそうです.
最後に
AddComponentは重いので気をつけよう,といった趣旨の記事でした.
そもそもMonoBehaviourの使用やAddComponent自体が比較的負荷の高い処理となるので,大量に生成する必要があるオブジェクトなどにはなるべく使用しないのが得策と言えそうです.