"Real Memory" isn't freed when changing scene on iOS

Hi, everyone.

I’m using Unity 3.4.2 Pro and developing iOS application.
I have a problem that seems to be a memory leak.
There are several questions about memory leak here, but these couldn’t help me.

My problem is very simple.
I change scene A to B, and then change B to A.
I expected that memory usage of scene A is almost same before and after changing scene.
But as far as I investigate with Xcode (Instruments), these are not same.

For making the problem simple, I prepared a project for testing.

  1. Create new project.
  2. Create two scenes named “A” and “B”, these have only “Main Camera”.
  3. Import the sphere model (.fbx) with approximately 10,000 polygons, vertex-colored, non-textured.
  4. Place the sphere model on scene “B”.
  5. Attach the script below to "Main Camera"s to draw button for switching both scenes.
  6. Edit the script variable “Next Scene” by Inspector. The value of scene “A” is “B”, and of scene “B” is “A”.
  7. Register these scenes for building and set “A” as default scene by “Build Settings”.
// SceneChanger.cs
using UnityEngine;
public class SceneChanger : MonoBehaviour {
    public string nextScene;
    void OnGUI() {
        if (GUI.Button(new Rect(0, 0, 100, 50), "to " + nextScene)) {
            Application.LoadLevel(nextScene);
        }
    }
}

I investigated real memory usage of each scenes by Activity Monitor (see this document), and results are below.

  • Scene “A”: 13.18 MB
  • Scene “B”: 15.55 MB
  • Scene “A”: 14.55 MB <= why?!
  • Scene “B”: 15.59 MB
  • Scene “A”: 14.59 MB
  • Scene “B”: 15.61 MB
  • Scene “A”: 14.59 MB

Does anyone have any hint or solution about this?

Thanks in advance.

I've investigated the memory behavior of Unity quite extensively to get to the bottom of why it seems to leak sometimes, and I feel I can take a stab at this question.

What you're seeing is very likely the effect of a non-generational Garbage Collector causing fragmentations in your heap. For more in-depth information, take a look at this link:

http://www.mono-project.com/Generational_GC

The short version is that Mono's garbage collector doesn't defragment memory when it frees variables. This means there are "holes" of available memory in between memory that is allocated to the process, and these holes cannot be returned to the OS when they are deallocated. Microsoft's garbage collector for .Net IS generational, so you'll see it returning memory to the OS in a smarter, more efficient way. I demonstrated that fact by creating a simple Winforms App in MS C#.Net and give it two buttons, one that adds 100.000 integers to a list, and one that clears the list again. By repeatedly clicking the add button, I saw memory increase. Clicking the clear-button returned memory to the OS as expected. Then I did the same in Unity, using GUI.Buttons to implement the same list behavior. But alas, Mono's garbage collector isn't that advanced just yet, so while the "Add 100.000 items"-button did cause memory to increase, clearing the list didn't return the memory to OS like MS C#.Net did.

You're seeing similar stuff in the above. When you move from scene B back to scene A, the sphere in B does get de-allocated, but because the garbage collector isn't "packing" the other variables to defragment the allocated memory, it cannot return it to OS. So it remains allocated to Unity. That's why Scene A now seems to take up more memory than before, and it is also why the memory increase goes back to approximately 15.5mb when you reload Scene B again. That's because the same sphere and scripts mostly fit into the holes they occupied before, so the runtime system didn't have to ask OS for more than 0.04 additional mb.

This fragmentation of the heap is a very serious problem, and you can go vote for the implementation of a generational garbage collector here if you agree it needs to be fixed:

http://feedback.unity3d.com/forums/15792-unity/suggestions/1067023-scripting-garbage-collection-sgen-gc?ref=title

Also be aware that static variables of monobehaviors are not deallocated when the game object is destroyed or a new scene is loaded.

For later version of Unity (4.3) please check this http://forum.unity3d.com/threads/227753-WWW-memory-leak-(iOS).

Basically Unity is not freeing memory on any AssetData loaded using WWW connections.