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

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):

public class Global : MonoBehaviour {
    private static Global instance;
    public static Global Instance {
        get { return instance; }
    }

    void Awake() {
        instance = this;
    }
}

After the object with the singleton script has supposedly been unloaded, I call the singleton’s function like this:

if ( GUI.Button( new Rect( x, y, width, height ), "Save and Quit" ) ) {
    if ( Global.Instance == null ) {
        print( "Global.Instance == null" ); // <--this is being printed
    } else {
        print( "Global.Instance != null" );
    }
    Global.Instance.MainMenu(); // <--this function is still getting called
}

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.

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.

Very helpful–I suspected it had something to do with the static-ness of my instance variable. I’ll try your suggestion. Thanks much!

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.