Mysterious coroutines between scenes

A story of spooky coroutine action at a distance.

So I had a coroutine, and I wanted to do some stuff, then switch scenes, then do some final stuff. This worked until the scene switch, then the coroutine never finished because the original MonoBehaviour wasn’t set as DontDestroyOnLoad, so it was deleted in the scene change. Fine, that makes sense.

But I thought, what if I called the coroutine via a MonoBehaviour script that was persistent? It should work, yeah? Well, except that the stuff that happens in the coroutine after the scene switch used private members on the original MonoBehaviour - the one that wouldn’t exist anymore after the scene switch.

It worked perfectly.

The original, non-persistent MonoBehaviour was still deleted, but the coroutine completed after the scene switch, despite using private members on the script that no longer existed.

Is this real life, or is this just fantasy? Will that cause a memory leak? I’m going to change it anyway because it’s a little insane. But for the record, apparently you can run some final stuff on a script as long as it’s in a coroutine in that script that you run via a separate persistent script. Sort of like a closure I guess? Would be interesting to know what actually happens internally in that situation.

This doesn’t sound too surprising to me. You have a reference to the MonoBehaviour with the private variables. As such the garbage collector leaves it untouched, but Unity knows it need to be destroyed and does it. At least the visible parts seem to be destroyed by Unity, but you still reference it.

Yeah, I was kind of wondering if it might end up like:

  • Coroutine runs
  • Scene changes
  • Unity does some sort of “remove scripts” pass. Oh no, that script can’t be removed because it’s still referenced from somewhere else
  • Unity removes it visually from the C# side but not the C++ side
  • Coroutine ends and drops its reference
  • It never gets garbage collected because Unity still has a reference to it

But hopefully, Unity drops all references from its side on scene change, the coroutine ends, and then it gets garbage collected and everyone is happy.

I didn’t bother actually testing for leaks because this method of doing things is a bit silly anyway.