Memory leak when loading and unloading scenes?

Hey everybody,

Right now I’m the process of trying to locate a incredibly annoying memory leak in a game where the game, in IOS, sometimes adds 5-10 MB to the memory around 1-20 seconds after loading a level. The game doesn’t add the MB’s to the memory instantly but once it starts it takes around 5 seconds.

I have spent around 8 days trying to profile the game and I still have not found the leak. I did however notice something that seems odd and wanted to see if I found a bug and if it could be the culprit in the memory leak I’m trying to fix.

I created a project where I have two scenes:

  • The startup scene. Has a camera, sprite and a game object with a script to load and unload the second scene
  • This scene contains only numerous boxes and spheres. Nothing more.

My script starts a coroutine that loads the second scene additively, waits 4 seconds, unloads the second scene, waits 4 seconds and repeats.

private IEnumerator MyLoaderRoutine()
{
  while(true)
  {
    yield return new WaitForSeconds(waitTime);
    if (!isInLevel2)
    {
      yield return SceneManager.LoadSceneAsync(loadedSceneNam, LoadSceneMode.Additive);
    }
    else
    {
      SceneManager.UnloadScene(loadedSceneNam);
      yield return null;
      yield return Resources.UnloadUnusedAssets();
    }
    isInLevel2 = !isInLevel2;
  }
}

I ran this project on my phone for 5:30, using Unity 5.4.4p1 and 5.6.0b11, and in both cases the memory does increase in the XCode debugger. I also tried this with UnloadSceneAsync and yielding to that but the problem was still there.

In the 5.4.4p1 build:
After approx 35sec, after unloading the second scene, the memory shows 59,3MB.
After 5 minutes and 30 seconds the memory is at 61.9MB after unloading the second scene.
(GIF: http://ellioman.com/temp/Unity544p1_Metal.gif)

In the 5.6.0b11 build:
After approx 35sec, the memory shows 47,6MB.
After 5 minutes and 30 seconds the memory is at 51.7MB.
(GIF: http://ellioman.com/temp/Unity560b11_Metal.gif)

Also made another test with 5.6.0 where the waiting time between loading/unloading was 15 seconds.
There it went from 38,9MB to 41,5MB
(GIF: http://ellioman.com/temp/Unity560b11_Metal_15sec.gif)

So my question is: Is this normal?

I exported the 5.6.0b11 project to a unity package if people wanted to test.
http://ellioman.com/temp/LoadSceneTest_Unity560b11.unitypackage

1 Like

That seems like a pretty insignificant difference. Here’s something to try… run GC.Collect() after unloading the second scene. My guess is that there is approx 59MB of stuff that’s still referenced in memory so it won’t go away… and another meg or two has been added but you haven’t yet hit the threshold necessary to trigger another GC collection cycle so, while those objects may not still be referenced, the memory is still allocated on the heap.

That’s not actually a leak… that’s by design.

Arg! Can not believe that I forgot to include the GC.Collect() call in the tests above, because I used that before and the problem is still there. That’ was the reason why I started to question whether this was by design or a bug. Because this is really tainting my search for the 5-10MB memory leak that does indeed crash my game.

I made two changes to the script:

  • I now use and yield to SceneManager.UnloadSceneAsync() when unloading
  • System.GC.Collect() called after unloading unused assets.

So my coroutine now looks like this:

private IEnumerator MyLoaderRoutine()
{
  bool isInLevel2 = false;
  float waitTime = 15f;
  string sceneToLoadName = "SceneToLoad";

  while (true)
  {
    yield return new WaitForSeconds(waitTime);
    if (!isInLevel2)
    {
      yield return SceneManager.LoadSceneAsync(sceneToLoadName, LoadSceneMode.Additive);
    }
    else
    {
      yield return SceneManager.UnloadSceneAsync(sceneToLoadName);
      yield return Resources.UnloadUnusedAssets();
       System.GC.Collect();
    }
    isInLevel2 = !isInLevel2;
  }
}

The Unity project in case someone is interested:
http://ellioman.com/temp/LoadSceneTestWithGC.unitypackage

I made two tests in 5.6.0b11. One for 5:30 seconds. Then another for 11 minutes.

Test 1
After 0:32 => 48,2MB
After 5:30 => 55,0MB
GIF: http://ellioman.com/temp/Unity560b11_Metal_WithGC_Duration_5min.gif

Test 2
After 0:32 => 48,2MB
After 5:35 => 55,5MB
After 11:00 => 55,9MB
GIF: http://ellioman.com/temp/Unity560b11_Metal_WithGC_Duration_11min.gif

So things don’t seem to change much after those 5:30 minutes.
Should I interpret that as “Move along, nothing to see here” or is the memory rise in the first 5:30 something that should be looked at?

Maybe make a post in the 5.6 beta forum for more visibility as devs are quiet active there…

Bonus:
Made another test using the same script but loading a scene in my game.

After 0:35 => 148,0MB
After 5:45 => 164,0MB
After 8:55 => 173,0MB
GIF: http://ellioman.com/temp/Unity560b11_OriginalGame_Metal_WithGC_Duration_9min.gif

Ahh didn’t realize that. I thought this made sense because this also happens in other versions.

Thanks for the tip, I’ll make another post there.