Performance of Component.gameObject, GameObject.selfActive, GameObject.setActive()

Hello,

Everybody know it’s not good to call gameObject.getComponent() in every frame Update(). We should call it at Start(), store the Component in variable, then we can access it any time in Update.

But how about component.gameObject? If we already have a component, does call this in every frame will affect performance? I don’t know what Unity does under the hood. Does Unity store the reference of the gameObject in the component, then return it immediately when we request? Or Unity must find or do anything else to return this property?

Similar to GameObject.activeSelf, it is a property, not a variable class field. I don’t know what Unity does when we call this. As I guest, it just returns a bool field immediately, does anybody know is this correct, or Unity must do something else before return this?

More, GameObject.setActive(bool) is a heavy duty if we call it every frame. It can lead to rebuild the whole Canvas if I call an UIElement.SetActive().
If an GameObject is already in status active=true, if I call setActive(true) again every frame: Under the hood, does Unity check it and do nothing? instead of doing all the heavy job?

Thank you.

Unity makes the C# source code available, for example here is Component.gameObject: UnityCsReference/Runtime/Export/Scripting/Component.bindings.cs at master · Unity-Technologies/UnityCsReference · GitHub

Namely it calls to Unity’s native (C++) side. So it has more overhead than a standard property, but I doubt much more than that.

In general don’t concern yourself about performance in your everyday coding. If acessing simple properties created such overhead, Unity wouldn’t be a particularly effective game engine. Obviously there are some simple best practices to follow, but also don’t overthink things.

Profile your game if you have a performance issue, and target the source of said issue.

No. We should get it in Awake !

Here’s the rundown:

  • Awake
    • new() C# classes
    • GetComponent(s)
    • GetComponent(s)InChildren
    • Assign references to static fields/classes (singletons)
    • avoid calling methods on these objects
  • Start or OnEnable
    • GetComponent(s)InParent
    • get references that are assigned in Awake to static classes or singleton instances
    • call methods of any reference you obtained

In short: Awake is for getting or new’ing references that the script can be certain of at this point, eg they are on the same object or children. In Awake you should not call methods of other references, perhaps with the exception of cases where you are absolutely certain that the object will not call out to, require or try to obtain external references - such as a static registry class that holds references and provides them to other scripts.

Start or OnEnable is for obtaining “external” (not in the active gameobject or its children) references and calling methods of any reference you obtained.

Profile it!

You can also Ctrl+click (“Goto Implementation”) the property or method in the IDE to inspect its (possibly decompiled) code. Usually in Unity you will find many of these are marshalled to native C++ code, that’s as far as we can (easily) see.

Generally, it’s best pratice to keep your code short and simple. DRY principle.

I often see code like this:

this.gameObject.transform.position = new Vector3(..);

Merely for legibility we should write it as follows:

transform.position = new Vector3(..);

It’s even worse with GetComponent. This is what we should write:

var targetScript = hit.Collider.GetComponent<TheTargetScriptThatINeed>();
if (targetScript.thisflag && targetScript.thatFlag == false && targetScript.counter > 10)
    // do something

Now imagine this … most newcomers don’t even bother to create the targetScript variable. Whether this is slower or not is practically irrelevant - it utterly makes the code above illegible and unmaintainable - that’s what matters!

Hence why best practice recommends using one canvas per each group of UI elements that change together. Eg don’t use a single canvas for the entire HUD, instead have one for the health bar, one for the team status, one for the minimap, and so on.

I recall from the past that it’s not “free” meaning if you first check isActiveSelf or isActiveInHierarchy you can avoid some extra processing. However, this really only matters in tight loops running every frame! The extra processing is most likely almost entirely due to marshalling the method call from C# to C++ - the transition between language barriers is not free.

There’s another situation however, which is more important to know about: if you instantiate several child objects, sometimes you don’t want them to start active. You may not even want them to run their Start/OnEnable methods upon first instantiation. The solution is to do this:

var wasActive = gameObject.isActiveSelf;
gameObject.SetActive(false);

    // instantiate many children here which are supposed to start inactive
    var child = Instantiate(..);
    child.SetActive(false);

gameObject.SetActive(wasActive);

Because the parent is inactive at the time of instantiating, the new instances are not starting their scripts which allows you to set these new objects inactive while instantiating. This can save needless initial processing (speak: loading) time if you only need one or few of these active (eg weapons) and switch between them.