x


Out of memory loading between levels

Howdy Unity gurus!!!

I get out of memory errors now and then just before loading scene "y" from secene "x". Scene"x" is moderate size, not tiny. Scene "y" only has two objects. One with a 1024 texture.

I'm trying the following:

Resources.UnloadUnusedAssets()

just before loading scene"y" but I'm not using any resource bundles. Would this have any effect? I'm assuming it would dump some memory.

Thx for any tips in advance on this issue.

more ▼

asked Jan 25 '12 at 04:37 PM

peter gravatar image

peter
371 37 38 40

Have you tracked the memory usage on Unity profiler or on the Windows taskmanager?

Jan 25 '12 at 05:44 PM luizgpa

Thx for your comment! On closer inspection, scene"y" has several object. about 15 simple planes, (billboards) and two guitext. Two boned skinned meshes. I looked at the profiler. Below is what is reported for memory. Does it look like enough to crash 4th gen iOS devices? I get occassional crashes that are stopped by cold start of device, but it's not a valid fix IMO.... Thx for any tips! scene"x" memory textures: 964 / 18 mb meshes 92 / 4.4mb total object count 14683

scene"y" textures: 959 / 10.3 mb meshes 41 / 285 kb total object count 2797

Jan 25 '12 at 06:06 PM peter

I'm sorry but I don't have much experience with iOS devices, so I will just throw some generic questions that came to my mind:

Does it crash if start your game loading scene "y" before "x"? Do you use LoadLevelAdditive or LoadLevelAsync? Do you have many static objects (like static var obj : GameObject) or objects using DontDestroyOnLoad?

Jan 25 '12 at 09:14 PM luizgpa
(comments are locked)
10|3000 characters needed characters left

1 answer: sort voted first

You can profile your memory usage using Instruments through XCode. Simply select Product > Profile from the menu bar, which will compile your app, put it on the device, and automatically open up Instruments (using XCode4, might be the same in XCode3). If you then select "Activity Monitor," you'll get a lot of data on the amount of memory you are using. Depending on your testing device, the acceptable amount of RAM varies.

iPhone3 (128MB total RAM): less than 40MB

iPad1 or iPhone3GS (256MB total RAM): less than 80MB

iPhone4, iPhone4S, iPad2 (512MB total RAM): less than 160MB

Another thing you might want to do is watch your XCode log and see if you are receiving memory warnings. Memory warnings are a pretty good indicator that you are using too much memory and the OS might shut you down.

Then, I've found the following code pretty useful to see everything that is loaded in memory at a given time. It will slow down your build a little bit because it uses UnityGUI, so use it for debugging only, not in production builds:

public class DetectLeaks : MonoBehaviour 
{
private static DetectLeaks instance;

void Awake()
{
    if(instance == null)
    {
       instance = this;
    }
    else
    {
       Destroy(this);
    }
}

void Start()
{
    DontDestroyOnLoad(gameObject);
}

    void OnGUI() 
{
    if(GUILayout.Button("Unload Unused Assets"))
    {
       Resources.UnloadUnusedAssets();
    }

    if(GUILayout.Button("Mono Garbage Collect"))
    {
       System.GC.Collect();  
    }

    if(GUILayout.Button("List Loaded Textures"))
    {  
       ListLoadedTextures();
    }

    if(GUILayout.Button("List Loaded Sounds"))
    {
       ListLoadedAudio();
    }

    if(GUILayout.Button("List Loaded GameObjects"))
    {
       ListLoadedGameObjects();
    }
    }


private void ListLoadedTextures()
{
    Object[] textures = Resources.FindObjectsOfTypeAll(typeof(Texture));

    string list = string.Empty;

    for(int i = 0; i < textures.Length; i++)
    {
       if(textures[i].name == string.Empty)
       {
         continue;
       }

       list += (i.ToString() + ". " + textures[i].name + "\n");

       if(i == 500)
       {
         Debug.Log(list);
         list = string.Empty;
       }
    }

    Debug.Log(list);
}

private void ListLoadedAudio()
{
    Object[] sounds = Resources.FindObjectsOfTypeAll(typeof(AudioClip));

    string list = string.Empty;

    for(int i = 0; i < sounds.Length; i++)
    {  
       if(sounds[i].name == string.Empty)
       {
         continue;
       }
       list += (i.ToString() + ". " + sounds[i].name + "\n");
    }

    Debug.Log(list);
}

private void ListLoadedGameObjects()
{
    Object[] gos = Resources.FindObjectsOfTypeAll(typeof(GameObject));

    string list = string.Empty;

    for(int i = 0; i < gos.Length; i++)
    {
       if(gos[i].name == string.Empty)
       {
         continue;
       }
       list += (i.ToString() + ". " + gos[i].name + "\n");
    }

    Debug.Log(list);
}

}

Finally, Resources.UnloadUnusedAssets() will only work if the asset is truly unused - that is, if there is no remaining script reference to the asset. If any Monobehavior is holding a reference, or if you have a link to a prefab that contains the asset, it will probably not be unloaded as a result of calling this. It is tricky to manage sometimes.

Hope this helps, and good luck!

more ▼

answered Jan 25 '12 at 09:39 PM

kromenak gravatar image

kromenak
2.1k 31 37 52

Thx so much! Very helpful tips!

Feb 02 '12 at 12:44 AM peter

Useful post - where do you get the numbers from for acceptable RAM?

Aug 23 '12 at 07:44 AM Bovine

Those RAM values aren't from an authoritative source; just my own observations/forum research and then extrapolating for newer devices. I probably got the most data with ipad1, where we were constantly battling memory crashes.

In my idealized world, "too much memory" is receiving memory warnings from the os. In practice, I've occosionally had to let it slip ;).

Aug 23 '12 at 08:10 AM kromenak

Thanks for the detail - that's fine, observations are as valid as anything and we're seeing some signal 9 issues and running at about 80MB I think. The trouble I am having at present is that the various metrics available give wildly different figures as to how much physical RAM is being used.

Our problem, I suspect, is that we have a memory intensive operation (compressing level data to save it between scenes) that allocates a lot of RAM during a blocking operation. I wonder if the application's main loop were allowed to run, whether Unity would handle the request more elegantly...

Aug 23 '12 at 08:57 AM Bovine

Yeah, I agree that the metrics given by the Unity profiler vs. the XCode profiler vs. a custom solution make it very hard to get an accurate picture of where your memory is going. I think this may be in part because Unity is pretty complicated, and it is storing things on the native heap vs. the mono heap. I've usually put more faith in the XCode profiler just because it is telling me what iOS is seeing, and iOS is the authority on whether my app gets terminated or not.

I wrote a blog post on this awhile back which, frankly, could probably be expanded a bit more with info on profiling. If you're interested though, there may be some helpful info: http://supersegfault.com/?p=43

Aug 23 '12 at 03:58 PM kromenak
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x870
x449
x11

asked: Jan 25 '12 at 04:37 PM

Seen: 7330 times

Last Updated: Aug 23 '12 at 03:58 PM