Search Unity

How to unload materials, textures and meshes from memory?

Discussion in 'Scripting' started by Evil-Dog, Oct 17, 2011.

  1. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Hey there, I'm baffled at how hard it seems to handle memory correctly in Unity.

    The type of game I'm working on had me separate different assets in different prefabs, sounds, sprites, animations, etc. which I instantiate and destroy once I'm done using them. I'm fine with the performance of all the instantiation and I call GC.Collect every now and then.

    The problem I'm facing is that the memory used goes up and never goes down. I've been tracking the problem and the number of textures, materials and meshes in memory just keep growing, never being released from memory. I end up in a situation where, gradually, it's like I had loaded every resources in the first place. And of course it crashes before that.

    Since it's not a level based game, I load prefabs with the stuff I need while I need it and then destroy those prefabs. The problem is say I play the "Eat an apple" animation, I load the apple animations, sounds, sprites, etc and then I unload it, but the material with the apple sprite stays in memory, I can destroy the material instances that are created but the actual apple material will stay in memory as an asset that I can't destroy. So then I load the "play with barbie doll" assets, and again, the barbie material is loaded in memory, I can destroy instances copied from that base material but not the base material, etc, etc, etc I end up with all the materials/textures loaded in memory, never to be released.

    Anyone has experience with unloading materials, textures and meshes out of memory once they're not used anymore?
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    1. Destroy / DestroyImmediate
    2. UnloadUnusedAssets

    thats it.

    GC will not change anything on unity assets as they are no .net objects, they are native code objects that have wrapper classes you interact with but are 100% managed through the unmanaged engine below.
    GC.Collect only helps with System.Object extended things like Strings and own datastructures etc, anything that extends from UnityEngine.Object is not under GC authority
     
  3. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Thanks
    But UnloadUnusedAssets is very slow and did not release the memory, would that mean they were still referenced somewhere or is there more to it?
    And when you say Destroy/DestroyImmediate, what do I destroy? I do destroy the prefab instances holding the assets and I can destroy the material instances that are created from the base material but I can't destroy or DestroyImmediate base assets like texture and materials (that are not instances). Especially not DestroyImmediate, it's very destructive in the editor.

    Thoughts?
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    You need to destroy anything that you loaded from Resources and instantiated.
    If you use AssetBundles, then the crucial thing not to forget is to unload the asset bundle.

    As for DestroyImmediate and editor: either just ignore it or use a
    Code (csharp):
    1.  
    2. #if UNITY_EDITOR
    3.   Destroy(..)
    4. #else
    5.   DestroyImmediate(...)
    6. #endif
    7.  
    if you are tempted to give a crap about the warning thats a consequence of the still messed up single .net environment messup with editor and play mode
     
  5. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Thanks for the answers dreamora, I don't use Resources.Load, if that's what you're refering to, and I don't use asset bundles. I simply use Instantiate on prefabs which will pull on their needed materials/textures. I destroy the prefabs after I'm done with them. Where does that leave me? I'd simply need to call UnloadUnusedAssets or do I need to somehow track what materials and textures are loaded to destroy them myself?
     
  6. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    you only need to call UnloadUnusedAssets.
     
  7. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Thanks I'll try again with UnloadUnusedAssets. It's pretty slow and causes a huge hiccup when I call it is there no alternate to manage the resources myself?
    And am I correct by assuming that since UnloadUnusedAssets is an async operation I could remove that hiccup and have it run in the background?
     
  8. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    if you don't use resources.load, where are you getting the prefab from?
    If its assigned in a variable, you are not 'dynamically creating' anything, you are only creating instances of it dynamically but the object iself is there none the less.

    Thats why Resources and AssetBundles exist, to load stuff when required and get rid of it when no longer required, because anything present and assigned in the scene is 'loaded' no matter if its visible and used.
     
  9. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    The variables point to prefabs. So the materials and textures are not loaded until I load those prefabs. Clearly shown by displaying all the materials in memory at any one point. When I load the prefabs the resources get loaded and then I do see the materials in the list of loaded materials by doing Resources.FindObjectsOfTypeAll(typeof(Material)) or Resources.FindObjectsOfTypeAll(typeof(Texture))

    That count goes up as I load new prefabs, I'm trying to get it down after destroying my instantiated prefabs.

    Just to be clear, I'm trying to fix my used heap going up and never down. Eventually the app crashes out of memory as new materials and textures are loaded, to the point where it's like I had loaded everything in the first place.
     
    Last edited: Oct 17, 2011