Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How does the static reference in Unity work?

Discussion in 'Scripting' started by lenamgiang, Sep 25, 2023.

  1. lenamgiang

    lenamgiang

    Joined:
    Apr 10, 2022
    Posts:
    4
    Good day, guys.

    I have 2 questions about static reference (like Singleton) in Unity:

    Situation 1: I have a bunch of game objects that have the same script that set static reference = this in its Start function. If Unity calls the game objects' Start function randomly in a scene then why is the first game object (the lowest child index, the highest game object in the hierarchy, you name it) always the only one referred?

    Situation 2: I have a script that has a static reference and it does not have DontDestroyOnLoad which means it will be destroyed after changing scenes, right? I call a function via the static reference in one scene alright, but when I change to a new scene, I'm still able to call its function despite the game object is destroyed and I also get null reference when I debug the call. Why is that?

    Thank you for your time.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    1. The order is not determined. Don‘t rely on it. It may change in a build, for each platform or just seemingly at random. Needless to say that such a static reference is pointless. Generally speaking avoid using static references whenever possible (= use rarely and judiciously).

    2. That is one reason why you should avoid static references. I assume what happens here is that the object is kept alive from the garbage collector (C#) point of view but it may have been destroyed on the engine (C++) side. It may throw a MissingReferenceException if you call methods on this reference.

    In the latter case, it‘s your responsibility to clean up (null) any static references before changing scenes. This adds to your mental load, the things to keep in mind. Since the field is static, it could still easily be accessed by other scripts, raising a NullReferenceException. Static fields are a common source of bugs, making the code brittle respectively heavily dependent, and hard to maintain.

    Also, try disabling Domain Reload as it makes entering playmode near instantaneous. This however requires special care for everything that is marked static (in code, not the inspector checkbox). See the manual, and give disable domain reload a quick try. I‘m sure you will not want to not use that as it speeds up iteration time so much. This is always the first thing I do in every new project.
     
  3. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,104
    Yeah, when an Object instance is destroyed, it doesn't actually become "null" or get released from memory at that point. Any fields on other objects that contain a reference to the destroyed instance, will retain a reference to it.

    Unity does some trickery to make it seem like references to destroyed objects become null. They have overloaded the
    ==
    operator on the Object class, so that code like
    if(instance == null)
    will return
    true
    for references to destroyed instances.

    Since the reference is not really null, you can still access any of its members without a NullReferenceException occurring. For example you could execute
    instance.GetType()
    or
    instance.MyCustomMethod()
    without any exceptions.

    It is only if you try to access any members implemented by Unity, such as
    instance.transform
    or
    instance.GetComponent<T>()
    , that a MissingReferenceException will oftentimes be thrown. This is because Unity has added code to most of the members that manually throws an exception if the object has been destroyed.

    So like @CodeSmile said, you need to manually assign a null value to the static property, if you want the destroyed instance to ever actually get released from memory on the C# side.
     
    CodeRonnie and lenamgiang like this.
  4. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    If you are implementing a singleton, you probably shouldn't have a bunch of instances of that script. Having one of the instances assign itself as the single, static instance can be useful when you have serialized an instance with certain property values in a scene so that it will be eager loaded when the scene loads. However, if any other bit of your code references the static instance property before the serialized instance in the scene has had its Start method invoked, most singleton implementations will lazy load and create a new instance, taking precedence over the one you have saved in the scene. These execution order issues are an inherent complexity in Unity to deal with when loading the app, scenes, and registering services such as singletons. Having many of them saved in a scene doesn't align with the concept of a singleton. Having one in a scene for eager loading can make a certain kind of sense in some situations.

    Usually a singleton implementation will include a null reference check when getting the value of the instance property. If you use the overloaded == operator that Unity provides, it should evaluate to null when destroyed, in which case a new instance is usually lazy loaded and re-created on the spot. If you do not intend to lazy load this singleton, and expect it to always be instantiated by the scene or some other source, then I would probably still have the null check and throw an exception. I would fail loudly at that point to alert everyone in development that something has gone catastrophically wrong, the kind of thing that cannot be allowed to happen after the app is released. Something is attempting to access a singleton during a period of time that amounts to an invalid operation exception, like when transitioning between the scenes that are the source of the instance of that static service.

    Getting all of these execution order based runtime issues worked out is one of the tricky parts of working with singletons, particularly those with serialized properties.
     
    Bunny83 and SisusCo like this.
  5. lenamgiang

    lenamgiang

    Joined:
    Apr 10, 2022
    Posts:
    4
    Sorry for my dumbness but I did not get your point.

    The situation I mentioned is just a test case (just my curiosity, not in practice nor for work) about the interaction between Unity's Start function and multiple static initializations. I know that the Start function is called randomly, depending on platforms and builds like @CodeSmile mentioned above, but I still don't get why it's always the "first" game object that is the one referred. And no, I don't call the static ref elsewhere, it's just "static ref = this", put in a Start function, and put in multiple game objects in a same scene and run at a same time.
    I get the ideas of singleton and lazy loading parts alright, but I'm also looking for a more detailed explanation of the "tricky parts" of Unity's Start function and static reference initialization.

    Thank you all for your replies!