Tuesday, January 03, 2017

Is the Unity3D GameObject.GetComponent method slow?

TLDR; No, not really.

Update: Actually, it is slow if you are using IL2CPP. Test results are GetComponent:350, Field:50, Dict:290.

Using the below test script, using GetComponent is about 3x slower than using a direct reference. Caching the return calue in a Dictionary, is slightly faster.

A typical result for me is 232 GetComponent(), 74 for private field and 201 for a dictionary lookup. If you use a builtin Unity type, like Transform, GetComponent is twice as fast.

I made sure the compiler was not optimising out my tests by putting in some fake 'xyzzy' work which is not included in the timing.

Why this simple test? I'm proving to myself it is not terribly bad to use a GetComponent call in an update loop, or keep a Dictionary cache. The call itself is so fast (0.000000232 seconds) that there is really no issue using it a few times inside an update loop.


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


public class GetComponentTest : MonoBehaviour {
    public int iterations = 1000000;

    GetComponentTest testComponentB, testComponentA;

    Dictionary<System.Type, Component> cache = new Dictionary<System.Type, Component>();

    void Start () {
        var sw = new System.Diagnostics.Stopwatch();
        for(var i=0; i<iterations; i++) {
            sw.Start();
            var r = GetComponent<GetComponentTest>();
            sw.Stop ();
            if(r.name == "xyzzy") {
                Debug.Log("xyzzy");
            }
        }
        Debug.Log(sw.ElapsedMilliseconds);

        testComponentB = GetComponent<GetComponentTest>();
        sw.Reset();
        for(var i=0; i<iterations; i++) {
            sw.Start();
            testComponentA = testComponentB;
            sw.Stop ();
            if(testComponentA.name == "xyzzy") {
                Debug.Log("xyzzy");
            }
        }
        Debug.Log(sw.ElapsedMilliseconds);
        sw.Reset();

        cache[typeof(GetComponentTest)] = GetComponent<GetComponentTest>();
        sw.Reset();
        for(var i=0; i<iterations; i++) {
            sw.Start();
            testComponentA = cache[typeof(GetComponentTest)] as GetComponentTest;
            sw.Stop ();
            if(testComponentA.name == "xyzzy") {
                Debug.Log("xyzzy");
            }
        }
        Debug.Log(sw.ElapsedMilliseconds);
        sw.Reset();
    }
}

No comments:

Popular Posts