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

Unloaded a scene, can still access one of its object's script components?

Discussion in 'Scripting' started by futurecrayon, Aug 13, 2014.

  1. futurecrayon

    futurecrayon

    Joined:
    May 7, 2014
    Posts:
    14
    I have a singleton script that is a component of a placed object in a scene. After I load a second scene (via Application.LoadLevel), I'm somehow still able to call a function of the singleton, even though the debugger tells
    me that the singleton instance is null.

    Shouldn't I be getting a null reference exception? Is the script, or the game object of which it is a component, somehow sticking around after the scene is unloaded? Any pointers on where to start looking would be appreciated!

    The singleton is implemented like so (lots of code snipped):

    Code (CSharp):
    1. public class Global : MonoBehaviour {
    2.     private static Global instance;
    3.     public static Global Instance {
    4.         get { return instance; }
    5.     }
    6.  
    7.     void Awake() {
    8.         instance = this;
    9.     }
    10. }
    After the object with the singleton script has supposedly been unloaded, I call the singleton's function like this:

    Code (CSharp):
    1. if ( GUI.Button( new Rect( x, y, width, height ), "Save and Quit" ) ) {
    2.     if ( Global.Instance == null ) {
    3.         print( "Global.Instance == null" ); // <--this is being printed
    4.     } else {
    5.         print( "Global.Instance != null" );
    6.     }
    7.     Global.Instance.MainMenu(); // <--this function is still getting called
    8. }
    Some notes on what I've already investigated:
    • The object which has this singleton script component is not in the second scene, nor is it preserved via DontDestroyOnLoad.
    • I confirmed that the singleton script is receiving an OnDestroy callback when the new scene is loaded.
    • I've placed breakpoints in the singleton's Awake call to make sure that it wasn't somehow getting instantiated multiple times.
    • If I load the second scene directly (not having gone through the first scene beforehand), I do get the null reference exception as I would expect. This seems to suggest that something is sticking around...
    • I'm somehow able to access a public member variable of the singleton class, after the singleton is supposedly destroyed. This particular variable is null until the singleton's Start function sets it. However, it is non-null when I am attempting to access it after the scene is supposedly unloaded.
     
    Last edited: Aug 13, 2014
  2. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,039
    Reloading a scene will not clear a static member variable. That structure is a C# structure which has no awareness of scenes, etc.

    Because your class is a MonoBehaviour Unity does some "finagling" to the object to make it report itself back as null once it has been destroyed (presumably overriding hash/equals method), even though it may still have references and is thus not GC'd. If you try to access MonoBehaviour methods you should see the "...has been destroyed but you are still trying to access it..." message.

    It depends on your use case but what you probably want to do is clear the static member variable when you get the OnDestroy().

    ----

    I will caveat this post with the fact that I haven't verified any of this, but it is based on my understanding/memory of a similar issue someone else posted a few years ago.
     
  3. futurecrayon

    futurecrayon

    Joined:
    May 7, 2014
    Posts:
    14
    Very helpful--I suspected it had something to do with the static-ness of my instance variable. I'll try your suggestion. Thanks much!
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,500
    Furthermore, nothing that happens on the native side of the engine destroys anything that exists in the Mono runtime. It just nulls out the references, and it's then up to the GC to come along and clean up the actual managed objects. This means that if you're referencing a managed object that's a part of a scene from somewhere outside of the scene (a static variable is one potential way to do this), unloading the scene will not result in the managed object being destroyed until you also clear the other references.

    It should also be noted that the managed objects are often wrappers for native stuff. So even if they're not null they might not actually have any data or otherwise be able to do anything.