Unity3d Work with memory: load and unload prefabs

14,397

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.

Share:
14,397
Admin
Author by

Admin

Updated on July 18, 2022

Comments

  • Admin
    Admin almost 2 years

    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.

  • Admin
    Admin almost 10 years
    Hi, Sergey. Big thanks for your reply. My problem with memory is next: my Unity app is embedded in XCode native application as a part. When i call first time Unity app from Main app, it starts, but when i need to go to main app, i call pause() unity. Memory of common app always increases when i load new scenes or load assetbundles. As result - when size of application becoming big - application fails with memory error.
  • Sergey Krusch
    Sergey Krusch almost 10 years
    I see. First thing to focus on here is to try to reduce texture's memory usage. Do you use texture compression? Is it possible to make some textures smaller without loosing in quality? Then you need to unload as much of the resources as possible before pausing Unity player. You can either try to call Resource.UnloadAsset on every resource (mainly textures) that is loaded (I have never tried this, but should work), or you can load some blank "Pause" scene and call Resources.UnloadUnusedAssets.