Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity3d Work with memory: load and unload prefabs

I'm really need help! I can't understand how to work with prefabs and unloading.

I have the next situation.

I run my application on IPad from Xcode. Unity version 4.3.1 Pro. Watch memory using with: Xcode Debug Navigator Xcode Instruments Unity Profiler

I do next steps:

0) Unity starts from Empty scene.

Used memory XCODE Debug Navigator: 11 mb Instruments: 26.4 mb Unity Profiler: used total 13.2 reserved total 13.7

1) Load prefab from Resources folder

prefab = Resources.Load("Room1"); 

Used memory XCODE Debug Navigator: 30.8 mb Instruments: 49.54 mb Unity Profiler: used total 19.8 reserved total 20.4

2) Instantiate prefab

go = (GameObject)Instantiate(prefab); 
go.name = "Room1"; 

XCODE Debug Navigator: 31.2 mb Instruments: 50 mb Unity Profiler: used total 20 reserved total 20.7

3) Destroy all objects on scene - memory not changed

Transform[] tr = FindObjectsOfType<Transform>(); 
for (int i = 0; i < tr.Length; i++) 
{ 
    GameObject goo = tr.gameObject; 
    if (goo.name != "Main Camera") 
    {
        Destroy(goo); 
        goo = null;
    } 
} 

XCODE Debug Navigator: 31.1 mb Instruments: 49.93 mb Unity Profiler: used total 19.8 reserved total 20.4

4) Call Resources.UnloadUnusedAssets(); - memory not changed

5) Call System.GC.Collect(); - memory not changed

6) Call UnloadAsset of prefab Resources.UnloadAsset(prefab); - memory not changed

7) Call Resources.UnloadUnusedAssets(); - memory partially cleaned

XCODE Debug Navigator: 21.9 mb Instruments: 40.79 mb Unity Profiler: used total 13.2 reserved total 13.9

In profiler i see, that deleted all texures, that used in prefab

8) System.GC.Collect(); - memory not changed

9) Load empty scene - memory not changed

Here is another interesting moment:

When application goes to background and i start another application, size of used RAM greatly decreases, and when i call unity app - memory goes to first size with empty scene.

I have next questions:

1) Why memory not cleaned fully after delete prefab and call UnloadUnusedAssets - we can see it in Instruments and Xcode - but in Profiler we see, that memory practically fully free?

2) It's real to clean memory to initial size?

3) Do i all steps right or i do something wrong?

You can download test project here: http://gfile.ru/aa5on

Big thanks for your replies.

like image 493
madmik Avatar asked Jun 06 '14 08:06

madmik


1 Answers

Preamble

It is good that you are aware of RAM usage. But, the question is: have you encountered any problems with memory usage so far? If not, then what you do is premature.

Some thoughts

Here are some thoughts for you to consider:

  1. Important article to read: http://docs.unity3d.com/Manual/MobileProfiling.html
  2. There is Unity memory and mono memory. Mono will never give back memory to OS:

    Once you allocate a certain amount of memory, it is reserved for mono and not available for the OS. Even when you release it, it will become available internally for Mono only and not for the OS. The heap memory value in the Profiler will only increase, never decrease.

  3. Prefabs and game objects are just a whole bunch of links, so they don't have such a large memory footprint as resources have.
  4. Object.Destroy doesn't destroy object instantly:

    Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.

  5. Resources.UnloadUnusedAssets is async. It doesn't unload everything instantly.
  6. It is not mentioned in Unity's docs that Resources.UnloadAsset(Object assetToUnload) will unload resources referenced by assetToUnload.

Explanation

I can't call myself an expert in memory management (of both Unity and Mono). But here is how I understand what's going on:

  1. 1) Load prefab from Resources folder

    Prefab was loaded with all the resources referenced by it. Memory usage increased. Everything is clear now.

  2. 2) Instantiate prefab

    Memory usage increased a bit to hold prefab clone.

  3. 3) Destroy all objects on scene - memory not changed

    Here come interesting things :) Actually, memory usage has changed according to Unity's profiler: it is the same as it was before instantiation of prefab. So, it looks like Unity has released something that was directly related to the prefab instance. But, as it is said, mono will not return memory to OS (and it's not even time for it to do so even if it did).

  4. 4) Call Resources.UnloadUnusedAssets(); - memory not changed

    Resources.UnloadUnusedAssets fails to unload anything here, because there are still no unused assets: though objects were marked for destruction, actual garbage collection hasn't took place.

  5. 5) Call System.GC.Collect(); - memory not changed.

    It's because it's memory managed by mono.

  6. 6) Call UnloadAsset of prefab Resources.UnloadAsset(prefab);

    I believe that memory usage has dropped a bit here (100K-200K or so) but you haven't noticed it. But, as I have mentioned above, UnloadAsset will not unload resources that referenced by object that you pass as a parameter to UnloadAsset.

  7. 7) Call Resources.UnloadUnusedAssets(); - memory partially cleaned

    On step 5 you have invoked GC.Collect(), collection has occurred and now some of the Unity assets have no references to them. Thus they can be freed finally. That's why memory has been freed.

  8. 8) System.GC.Collect(); - memory not changed

    Explained above

  9. 9) Load empty scene - memory not changed

    Everything that could be freed have been freed already. Thus no change in memory usage.

like image 105
Sergey Krusch Avatar answered Sep 20 '22 12:09

Sergey Krusch