Search Unity

UnityEngine.Object.name allocates for each access!

Discussion in 'Scripting' started by numberkruncher, Mar 31, 2014.

  1. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    951
    Hey guys!

    This may be common knowledge which I have somehow overlooked, but I have just discovered that whenever I access "name" from a game object or component it actually allocates memory!

    For instance, in the following case the same string is allocated three times:
    Code (csharp):
    1.  
    2. if (go.name == "A") { ... }
    3. if (go.name == "B") { ... }
    4. if (go.name == "C") { ... }
    5.  
    I am a little surprised that Unity is not just keeping a cached copy of the name string, and then updating that each time a new name is assigned.

    Anyhow, just thought I would post about this in case this is of interest to anybody :)
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,663
    Yeah... .name is one of those "funny" property that do weird call to Unity's native code. I even had it returns me nulls and undefined a few times.

    It tends to returns the file name of the asset, or the GameObject's name.

    I try to stay away from it as much as possible and implement my own "Name" property when I need to name something.
     
  3. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    951
    If there is a Unity developer reading this... what about implementing UnityEngine.Object.name something like this?
    Code (csharp):
    1.  
    2. private string _cachedName;
    3. public string name {
    4.     get {
    5.         if (_cachedName == null || ExternalHasNameChanged())
    6.             _cachedName = ExternalGetName();
    7.         return _cachedName;
    8.     }
    9.     set {
    10.         ExternalSetName(_cachedName = value);
    11.     }
    12. }
    13.  
    In managed-land this avoids unnecessary allocations, yet unmanaged-land can still change the name if desired. Just needs to set an internal flag each time the name is changed.
     
    TheRealTomKhan likes this.
  4. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,663
    Probably because you shouldn't be relying on .name for anything at runtime.

    The only time I found this property useful was in editor mode.
     
  5. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    951
    It is in the documented API, so it should be reliable!

    It totally spams memory allocation in-editor when object names are shown within OnGUI.

    The above suggestion to cache the .name string (and indeed, the same goes for the .tag string) should be fairly easy to add, and will help those who do want to use these things in their games (or indeed in-editor). I appreciate that there is a CompareTag function, but .tag shouldn't allocate for each access either.
     
  6. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,663


    I can't really argue against that. However, considering how many of the method/properties in Unity's API are very poorly documented...
     
  7. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    Are you sure? Maybe you allocated a string when you do the comparison. When you type a string in double quotes, you are allocating a string. I don't it (the allocation) happens when you access that name field. The latter effect does not make sense to me.
     
  8. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    951
    It does allocate and it is easy to test, just run this in the profiler and watch the allocation count ;)
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class NewBehaviourScript : MonoBehaviour {
    5.  
    6.     void Update() {
    7.         string foo;
    8.         for (int i = 0; i < 10000; ++i)
    9.             foo = name;
    10.     }
    11.    
    12. }
    13.  
    ".CompareTag" provides better performance than ".tag" since it avoids these allocations.

    But in my opinion these allocations could be avoided altogether by retaining a cached reference inside the managed object.
     
  9. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    It seems that you are just setting one reference type to another (I know strings are immutable, but that example doesn't seem to require the creation of a new string if you don't take Unity magic into account).

    Which section of the profiler are you looking at? Are you taking a sample and looking under a particular item?

    edit: I see that you are looking under the CPU usage part. I'm not sure why the allocation would happen when you access that field.
     
    Last edited: Apr 28, 2014
  10. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,663
    No need to look at a profiler to understand... "name" is not a field, it's a property which fetch an internal unmanaged C++ string. Every time you call it, it creates a new managed instance. UnityEngine.Object does not contain a cached instance of that object.
     
  11. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    951
  12. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    In my case I might require caching for the name field, not just for .transform. And here I thought accessing transform was bad due to performance. They never mentioned the .name field before, maybe because the hit was a quite small (even though it can add up). I suppose accessing .name would access a bunch of a cycles too (like .transform)?

    Do all fields require aching? like the .gameObject property

    edit: misread your post in regards to caching of .Object
     
    Last edited: Apr 28, 2014
  13. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    Thanks. After some looking around the profiler I came to the same conclusion and cached the name (see my post edit)
     
  14. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,663
    Usually, if you use .name at runtime, you might want to redesign your code flow. The only moment I needed to find an object by name is when searching for a bone, and even then I don't use .name but use GameObject.Find or Transform.FindChild which is a call to a unmanaged function which leaves no garbage behind.

    .name is more useful in Editor mode while handling files around.
     
    MonomiPark likes this.
  15. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    My scenes have a (finite set) of certain objects that are named and distinguished by name. Basically multiple objects based on the same prefab. I could assign a unique id to them, or I could cache the name property. The latter makes it easy to relate to the code to named objects in a scene. Based on how my game is set up, it makes sense.

    I think I will cache the name property.
     
  16. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    I believe it's because technically you're calling a getter method when you call name, not the variable itself. Since a getter method could conceivably return a different result each time, it allocates different memory for each result. It has no magical way of knowing the result will always be the same. I can't imagine it has any real performance hit, but I'd also already learned to cache on my own without relying on interpreter magic.

    To be clear, if you're going to use a property from another object more than once, you store it in a local variable. I think that's just normal for object oriented programming.
     
  17. bleu

    bleu

    Joined:
    Apr 6, 2013
    Posts:
    41
    I guess based on my background (C++) I'm more used to calling classic getter functions (not properties that "look" like a variable name) and expecting those pieces of code to not be fast. Based on that fact, I normally cache stuff in C++.

    With properties accessed inside of C#, yes, some extra stuff can go in the background that people occasionally will not think about if they don't know how their C# code works in relation to the Unity engine (and if they are not aware of any costs associated with properties). While I cache the transform properties, as well as various components (physics, audio-related, etc) that are necessary, it makes sense to me that the .name property is something that has a cost associated with it. In the my special case, I have some objects that never change names in a scene, so caching their names would be a good idea.
     
    Last edited: Apr 28, 2014
  18. Smooth-P

    Smooth-P

    Joined:
    Sep 15, 2012
    Posts:
    214
    For how bad allocations are in Unity, UT doesn't seem to put much effort into avoiding them.

    Time for more boilerplate...
     
    twhittaker likes this.
unityunity