Search Unity

Yet another Resources.Load question

Discussion in 'iOS and tvOS' started by camille, Apr 30, 2010.

  1. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    Hi,
    I can't seem to unload resources I load. I narrowed the problem to a simple script, in an empty scene :

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CrawlMemory : MonoBehaviour {
    5.     private GameObject myGo = null;
    6.  
    7.     void OnGUI () {
    8.         if (myGo != null) {// Resource is in the scene
    9.             if (GUILayout.Button("unload")) {
    10.                 _UnLoad();
    11.             }
    12.         } else { // Resource is not in the scene
    13.             if (GUILayout.Button("load")) {
    14.                 _Load();
    15.             }
    16.         }
    17.        
    18.         // button to force the CG to run
    19.         if (GUILayout.Button("CG collect")) {
    20.             Application.GarbageCollectUnusedAssets();
    21.             System.GC.Collect();
    22.         }
    23.     }
    24.    
    25.     // This loads a random resource
    26.     private void _Load () {
    27.         // Resources are named res1 through res9
    28.         myGo = (GameObject) Instantiate(Resources.Load("res" + Random.Range(1,10).ToString()));
    29.     }
    30.    
    31.     // This tries to unload the resource
    32.     private void _UnLoad () {
    33.         Destroy(myGo);
    34.         myGo = null; // This was the only reference to the instantiated resource.
    35.     }
    36. }
    I run this through Instruments on the iPhone, with an empty scene and this script attached to the main camera. I have 10 random resources in the Resources folder (they are GameObjects with random components attached to them, just to test.)

    When I press load, the memory goes up, as expected. When I press unload, the memory doesn't go back down, as expected with a GC managed memory.

    But when I force GC collect, the memory doesn't goes down either. When I load other random resources, they just pile up in memory, even if I load another scene afterwards...

    This is driving me nuts, as my project heavily relies on dynamicaly loaded resources, I often run low on memory.

    Please help !
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    gc collect has no importance to unity engine object only to System.* stuff at least unless you cleared all references.

    Use the purge function in the application class instead
     
  3. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    What purge function ? Do you mean Application.GarbageCollectUnusedAssets() ? I do use it when I press the "CG collect" button in the script.. It does nothing in my case.

    Is there another purge function I am not aware of ?

    Thanks for the quick reply
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Right, that function

    If it does not remove the memory then its still active. Try a DestroyImmediate(...) to ensure its killed right away not at a later point in case its a timing thing.

    And ensure that the resource related stuff does not prevent it from being gone (a scriptless GO would make a good test to see if it is related to scripts attached or not)
     
  5. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    Thanks for the reply !

    I tried DestroyImmediate but it did not change anything.

    I narrowed the problem event further. I made big random textures (1024 x 1024, RGBA32 format, ~5mb in memory), and tried the following :


    - I made prefabs with a GUITexture component, with these textures; CollectUnusedAssets seems to clean the memory once I have Resource.loaded / Instantiated / destroyed the instance.

    - I made a sample script (see below) with a public Texture2D, and did the same as with GUITextures : CollectUnusedAsset does not clean the memory after I destroy the prefabs. Even worse, the memory stays high event after a complete scene change.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ImagePrefabTest : MonoBehaviour {
    6.     public Texture2D img;
    7. }
    8.  
    I use this a lot (making prefabs with custom components attached to them, which links to textures, sounds, ... and load the prefab at runtime), so this makes huge memory leaks in my projects.

    I'm using Unity iPhone Advanced 1.7.0.

    What am I doing wrong ?


    Thanks,
    Camille
     
  6. arzi

    arzi

    Joined:
    Apr 6, 2009
    Posts:
    154
    I have a bit similar situation with our tutorial images (fullscreen 480x320 images), I use Resources.Load to load them and then clean them up to free memory for the next images.

    It seems that the following helps:

    * Replace the GUITexture's texture with a placeholder image (i.e. new Texture2D(1,1))
    * Run both Application.GarbageCollectUnusedAssets and System.GC.Collect.
     
  7. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    Hi Arzi,

    I tried to replace the texture with a new Texture2D(1,1), even tried to replace the instantiated GameObject with a new GameObject(), but unfortunately that did not solve anything.

    I was already doing that, hoping that it would work...

    Thanks for the advice
     
  8. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    Here is a sample project to reproduce this, with the 2 scripts mentionned above, the scene and placeholder prefabs.

    When I run this through Instruments, memory is never cleaned up, even after a scene reload.

    Thanks for the help
     

    Attached Files:

  9. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Hi Camille,

    Even we are facing the same problem here. and we are not able to release the memory even after switching from one scene to other.
    Have you found the solution for this bug yet?
     
  10. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    Unfortunately I have found no solution. I am currently using asset bundles as they provide the Unload feature, but I am not happy with that solution (it uses way more CPU and memory).
     
  11. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    Hi Camille,

    So ur loading all the resources via internet?

    Is it possible to load the bundle assets from the Device directly rather than fetching from web-server?

    Can you help me out with it, as I have never used asset bundles.


    Another thing I have reported this issues to Unity3D using report tool provided by unity. and w8ing for a proper solution. Hope they can provided a better way to handle it
     
  12. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    The WWW class supports the file:// protocol on Unity iPhone. Here is what you have to do :

    - Package your assets into bundles using editor scripts (the example project should help you : http://unity3d.com/support/resources/example-projects/assetbundles . It's for Unity (not iPhone) but it works the same way)

    - Put your asset bundles into the iPhoneStreamingAssets folder : the will be copied in the .app in the Data/Raw folder !

    - Get the proper file:// link to load the asset. I use this :

    Code (csharp):
    1. public static string GetAssetBundleBasePath () {
    2.         if (Application.isEditor) {
    3.             return "file://" + Application.dataPath + "/../iPhoneStreamingAssets/";
    4.         } else {
    5.             return "file://" + Application.dataPath + "/Raw/";
    6.         }
    7.     }
    - Load the AssetBundle, keep a reference to it

    - When not needed anymore, Unload(true) the AssetBundle. No memory leak !



    But be careful, it uses more CPU and memory (it has to load the compressed data, uncompress it and serialize it). This is why I want to use the Resources.Load way...

    I submited a bug report too, but no answer yet.

    Hope that helps

    Camille
     
  13. Big Pig

    Big Pig

    Joined:
    Feb 21, 2009
    Posts:
    92
    Sadly this issue remains in 3.0... Unity guys, will you PLEASE address this? Do I really have to use AssetBundles if I don't want objects to remain in memory?

    I won't even submit a bug report, because so many regarding this issue have been submitted.
     
  14. camille

    camille

    Joined:
    Feb 23, 2009
    Posts:
    47
    If this is true, this is really sad. I was hoping for the 3.0 release to make my game actually work as intended. All of the new features are nothing if memory is not properly managed. Please someone tell me it's not true...
     
  15. Big Pig

    Big Pig

    Joined:
    Feb 21, 2009
    Posts:
    92
    Good news!! Resources.UnloadUsedAssets is now supported on the iPhone (in Unity 3.0). I tested it and it works (I can see it doing its magic in Leaks and Activity Monitor).

    :D :D :D

    I'm really glad I don't have to use bundles. The memory shot up sky high whenever I loaded one and when I unloaded it, it never got back to where it was before.
     
  16. AbhishekS

    AbhishekS

    Joined:
    Dec 15, 2008
    Posts:
    157
    @Big Pig: check if the object allocation stack is also getting down once you use destroy function and you switch levels/scenes.

    if not than the bug is not yet fixed at all.
     
  17. Big Pig

    Big Pig

    Joined:
    Feb 21, 2009
    Posts:
    92
    If they're getting destroyed within the scene, I can assume that they'll stay destroyed even when I switch scenes... is this what you mean?