Does GetComponent have a big impact on performance?

Hello, tell me, I heard that GetComponent greatly affects performance, how much is it true?

  • Spin-up the profiler
  • Try doing a loop with a lot of GetComponent calls
  • Look at the performance results on your machine(s)/device(s)

Ensure you read a component and store the reference to it away rather than constantly retrieving it. Nothing is free, performance-wise

But if you want someone to tell you if “X” is fast/slow in absolute terms then you won’t get an answer. At least, you won’t get a useful answer. Anything can be slow if used incorrectly so it’s all about context.

Many new devs write code that constantly (line to line) repeat the same thing like retrieving a transform component to read its position to read the X component to then do the same again on the same line for the Y component and even worse in subsequent lines. It’s not free but it’s also not that expensive. It doesn’t mean you should abuse it so the answer here is, my first three steps. :slight_smile:

2 Likes

Note that GetComponent has some quite insane behavior in the editor (instantiating editor-only error objects), so profile it in builds if you’re going to profile it.

You have to use GetComponent (or TryGetComponent) in order to get components from gameObjects. It takes time to do so, but you can’t really use Unity without the method unless you’re doing very convoluted design.

The advice really is “GetComponent to get a thing has a larger cost than keeping a reference to the same thing, so if you’re looking it up multiple times, caching the results is faster”. A lot of people cargo cult that to “GetComponent bad”.

7 Likes

My rule of thumb for choosing whehter to cache GetComponent result typically goes something like this, same principle also applies for other not very fast (but not exactly slow) functions

  • If you are calling getComponent each frame in Update, that you have hundreds of objects, you should probably cache it and not call getComponent from update
  • if you are doing a few getComponent calls during initialization of object it’s not a problem, creating the object was probably more expensive
  • If you are calling getComponent as reaction to user input that will happen once every dozen seconds, or maybe even once every few minutes. For example opening a menu, interacting with ingame object, doing scene transition. Most likely safe to call it directly, no need to complicate code. Having a few dozen GetComponent calls within frame probably won’t even cause a minor stutter and even if it did for rarely performed action that cause major screen transition that might be acceptable.
  • If you would have to keep multiple references to the components of the same external object just to avoid additional GetComponent calls, probably safe to just keep single reference and call GetComponent or restructure the code so that you are only directly interacting with single component of that object. Too much touching internals of other objects (accessing many components or properties) is a code smell.
  • if you will access the same compoment multiple times in a row, save it local variable. Not only will save GetComponent calls but it might also make the code more readable by not having it excessively long lines. Don’t push this to cargo cult level, it’s fine to use getcomponent result directly if you will do it once and the line isn’t too long.
  • Everything between is grayzone, cache when when it’s easy to do, don’t if it would significantly complicate the code or slowdown the development process. And rely on profiling to catch the remaining case that should have been cached if you notice performance issues.

In summary having total few dozen GetComponent calls per frame from all the objects is not a problem, only when every object does it every frame, or you are doing it in a loop on hundreds of objects you will start to have issues. Unlike memory allocations this won’t even accumulate.

7 Likes

For perspective:

I did a test a while back where I replaced this common pattern:

void OnCollisionEnter(Collision collision)
{
    MyComponent c = collision.collider.GetComponent<MyComponent>();
}

with:

public static Dictionary<Collider, MyComponent> componentDict;

// MyComponent OnEnable registers itself in the dictionary

void OnCollisionEnter(Collision collision)
{
    MyComponent c = componentDict[collision.collider];
}

With 10,000 colliders in the scene (and thus in the dictionary) the second version was still fifteen times faster than the first.

However

Whether that matters or not really depends how many times it’s happening. In my extremely collision-heavy scene it saved thirty milliseconds. If it’s happening just a handful of times, forget it.

6 Likes

i have not taken the concept as far just building a lookup table of everything, but for raycasts or collisions on rapid fire type things i will cache both the component and collider from the last hit, then on the next hit if the colliders match i do not bother with GetComponent and used the cached one.

The value of the dictionary increases if you are not able to use collider tag to fully identify what you’re hitting, and need to speculatively try to get components to interact with. At that point, I make the dictionary <Collider, ComponentWrapper> where ComponentWrapper contains direct references to the various components I might be interested in.

Then if (collision.collider.GetComponent<Blah>()) becomes

ComponentWrapper wrapper = dict[collider];
if (wrapper.blah){
}

Unfortunately this page is a top hit on Google, I was hoping for a solution :). But since there isn’t one, I can share some experiences…

Compared to a random piece of code GetComponent is fast - but considering how frequently we have to use it in a typical Unity project: they could be better.

Note: Editor GetComponent is not the same as Runtime/Player GetComponent (off the top of my head: Editor version maintains extra state to help you debug / understand error messages inside the Editor, etc). In editor you should never use “GetComponent” for anything. Instead use TryGetComponent (which not only is faster – it avoids allocations when the result is ‘null’ – but also is implemented differently and bypasses at least one bug that exists in GetComponent where GetComponent can consistently give incorrect results). Oh - and: it’s better C# code (TryGet is better than Get-and-check-for-null, which we use often in Unity).

Like @Peeling above I implemented caching (although I did a more full-featured cache, with the ability to self-empty and manage its size, etc) and got orders-of-magnitude speed increases. Make sure you get your GetHashCode correct on whatever you’re using as key, as that can slow it down (for large dictionaries you can lose some/most/probably all the speed increase if you have a poor GetHashCode).

EDIT: I’m a fool, for the bit that I wrote at end about performance (now removed, because it was wrong): I had a much bigger problem than GetComponent - OnEnable was spamming GetComponent calls. I had hundreds of thousands of calls instead of the hundreds I thought. Oops!

1 Like