こんにちは、Unityエンジニアのオオバです。

最近多い、ふと気になったシリーズです。

昔(2~3年前)はtransform.localPosition = Vector3.zero;のようにtransformプロパティは直接アクセスすると、GetComponent()が内部的に実行されていて、処理負荷的に重いからキャッシュした方が良いよ!っていう話をよく聞きました。

じゃあ、最近のUnityはどうなっているか?

  1. transformプロパティにそのままアクセス
  2. GetComponent()を記述してアクセス
  3. transformをキャッシュしてアクセス

この3種の方法で確認します。

結果

transformの取得に最適化がされていた件_0

1.transformプロパティにそのままアクセス3.transformをキャッシュしてアクセスがほぼ同じくらいの負荷(ただしキャッシュが最速)。
2.GetComponent()を記述してアクセスが最遅という結果になりました。

プロファイラーのDeep Profileで内部処理を確認してみます。

方法Transformアクセス処理ざっくり処理時間
1.transformにそのままアクセス
transformの取得に最適化がされていた件_1
5.15ms
2.GetComponent記述アクセス
transformの取得に最適化がされていた件_2
7.62ms
3.transformをキャッシュしてアクセス特になし3.79ms

このようにtransformプロパティアクセスは内部的にGetComponent()ではなく、最適化され、get_transform関数が実行されているようです。

検証コードはコチラ

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using UnityEngine.Profiling;  

public enum TransformAccessType  
{
    transformAccess,  
    GetComponentAccess,  
    CachedTransform,  
}

public class TransformTest : MonoBehaviour  
{
    // インスペクタから切り替えて負荷確認  
    public TransformAccessType type;  
    Transform t;  

    void Update ()  
    {
        if (t == null)  
            t = transform;  
        Profiler.BeginSample ("######");  
        for (int i = 0; i < 10000; i++) {  
            if (type == TransformAccessType.CachedTransform)  
                t.localPosition = Vector3.zero;  
            else if (type == TransformAccessType.GetComponentAccess)  
                GetComponent<Transform> ().localPosition = Vector3.zero;  
            else  
                transform.localPosition = Vector3.zero;  
        }
        Profiler.EndSample ();  
    }
}

まとめ

ガリガリチューニングするなら、昔ながらのTransformキャッシュが最も良いですが、transformアクセスもそこそこ最適化されているため、普通に使っちゃっても大きな問題はでないだろうという見解です(状況次第)。Transformアクセスの処理方法が変わったということが分かった事が今回の調査で良かったことです。

ブログを書き終えた辺りで見つかるこのような記事。

gameObject.GetComponent() と transform の違い(または Unity における省略記法について) - Qiita

なるほど、2017.2辺り時点でtransformプロパティの最適化が入っていたようですね。

オススメ記事
検証環境