Garbage Collection

I have a game that loads a series of fairly complex animated characters from prefabs. When a new character loads, I Destroy() the previous one. Watching the Real Memory value in the Activity Monitor instrument, I see each character taking up about 4 meg when it’s loaded, and then never giving it back when it is destroyed…each subsequent character just takes more ram until the app crashes.

I tried issuing these after the Destroy() call, singly or together:

Application.GarbageCollectUnusedAssets();
System.GC.Collect();

…but it crashes the iPod when I do. It works fine in the editor though, with no errors reported in the console.

Does anyone know what I need to do to free up the memory?

The thing about Garbage Collection is that you can’t fully control it.
Destroy() should cause the memory to get freed, and
Application.GarbageCollectUnusedAssets() should cause it to get freed sooner rather than later, but it’s not going to happen immediately. This is vague I know and probably doesn’t help your situation. Maybe the System.GC.Collect() is causing the crash?

It seems to be the

Application.GarbageCollectUnusedAssets();

crashing it. when that runs, I see the memory allocation climb until the application crashes.

:frowning: :frowning: :frowning:

Do you have any finalizers that could be causing that memory leak?

No…no finalizers at all.

It seems like any prefab you load just stays in memory after you Destroy the game object. Multiple instances of the prefab use just slightly more memory…which is cool. Unfortunately the game I am working needs to load a series of pretty big character animations, and I need that memory back.

I’ve also tried Application.LoadLevel(0), thinking that might free things up, but that actually crashes on the iPod too…just starts devouring memory until it’s all gone.

You perhaps should show some code that replicates that.
From theory there are as many reasons as there are reasons that are totally stupid and impossible so what we do here is blind guessing.

If you can’t show the code here, you will have to file a bugreport (thought I assume you already did that anyway)

I did file a bug report. I can’t post the prefabs, but here is the script that replicates the behavior. Populate the prefab array with a few fat, juicy prefabs, then use the buttons to step through. Then watch the task memory in the activity monitor.

using UnityEngine;
using System.Collections;

public class LoadTest : MonoBehaviour {

	public GameObject[] prefab;
	GameObject current;
	int i = 0;
	
	void Start()
	{ Physics.gravity = new Vector3(); }
	
	void OnGUI()
	{
		if( GUI.Button(new Rect(0,0,100,50), "up") )
		{
			i++;
			if(i >= prefab.Length)
				i = 0;
			
			Set(i);			 
		}
		
		if( GUI.Button(new Rect(220,0,100,50), "down") )
		{
			i--;
			if(i < 0)
				i = prefab.Length - 1;			 

			Set(i);			 
		}
		
		if( GUI.Button(new Rect(110,0,100,50), "pause") )
		{
			if(Time.timeScale == 0.0f)
				Time.timeScale = 1.0f;
			else
				Time.timeScale = 0.0f;	
		}

		if( GUI.Button(new Rect(0,380,100,50), "GC") )
			System.GC.Collect();		

		if( GUI.Button(new Rect(220,380,100,50), "AGC") )
				Application.GarbageCollectUnusedAssets();

		if( GUI.Button(new Rect(110,380,100,50), "Scene") )
				Application.LoadLevel(0);


	}
	
	void Set(int i)
	{
		if(current)
		{
			Destroy(current);
		}	

		current = Instantiate(prefab[i], new Vector3(), Quaternion.identity) as GameObject;
	
	}
	
}

Try to replace

if(current) 
{ 
  Destroy(current); 
}

with

if(current) 
{ 
  UnityEngine.Object.Destroy(current); 
}

or alternatively

if(current) 
{ 
  UnityEngine.Object.DestroyImmediate(current); 
}

also you should not forget that everything in prefab is instanciated all the time so if your target is to save memory, create a folder “Resources” in your asset folder and put the assets in there.

then you can create new stuff dynamically throught

Instantiate(Resources.Load(“someResourceName”), … )

instead of holding all objects in memory all the time

Dreamora,

Thanks for that tip - I have been getting the odd Warning for memory on my little iPhone game which uses prefabs for ALL my levels (18 in all).

I am hoping that what you have posted here will help my game a lot. I shall of course keep you posted.

Thanks for the suggestions. I tried:

…but there was no change.

I don’t think this is the case on the iPhone. When I initally load the app without instantiating anything, real memory is at about 17meg. Once I start instantiating characters, each on grabs another 4 meg and keeps it.

I tried Resources.Load, and got the same behavior.

Is real memory what I should be looking at, do you think?

With about 25 to 30 MB usage, you are in a “safe area” normally and shouldn’t be worried.

Unfortunately, after about the third character, I’m no longer in that safe area…and after about the 6th character, it crashes.

Did you restart your device?
Because otherwise, you can get into situations where even “base assumptions” will fail.

This is not unique to Unity. The iPhone OS has some pretty serious problems with freeing the application sandboxes fully.

Also it naturally differs seriously between devices. If you have a 1st generation ipod touch, then you are in a pretty bad situation when compared to a 2nd generation ipod touch.
Even thought only the CPU so far is proofen to be stronger on the new devices (especially 2nd generation ipod touch), there are different reports on the web that the 1st generation ipod touch seems to have (considerably) less RAM to use within apps for example.

How much RAM are you using after the 3rd character?
Also are they animated and different materials?

Yes…the poor thing has been restarted a few dozen times in the last couple days.

I have a first gen iPod touch.

50mb, after destroying all instances.

Yes, they are animated, and all have different materials.

With a first gen iPod Touch you reached about the border.
40MB is more or less safe on it, between 50 and 60MB you go further than you must on it.
You will either have to cut your content or get a 2nd generation ipod touch or an iphone (and restrict it to the newer devices which means all but 1st generation ipod touch)