Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[Solved] Texture memory piling up

Discussion in 'iOS and tvOS' started by redd, Mar 8, 2010.

  1. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    So I'm trying to load in images directly off of the iPhone into a Texture, and although it's working, my memory usage increases significantly for each texture I load, and I can't ever recover that memory once I'm done with the textures.

    If it was a one-time memory hit that could be fixed once I was done with the pictures, I'd be completely okay with that. The problem however, is that once I've loaded the images/textures, I can't seem to remove them from memory!

    I'm loading images as so:

    Code (csharp):
    1. var fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
    2. var thebytes = new byte[fs.Length];
    3. fs.Read(thebytes, 0, fs.Length);
    4. fs.Close();
    5. texture.LoadImage(thebytes);    
    6. thebytes = null;
    7. fs = null;
    As you can see, I try nulling out what I've opened. Later, onDisable of the object that's using the textures, I clear the texture, and clear an array of textures that were holding the multiple textures I load in with this method.

    Still, I can't seem to get rid of the memory usage (and I've tried GC collection force, too.)

    If anyone can tell me how to kill these unwanted textures out of memory, I'd much appreciate it! I need to be able to dynamically load multiple filesystem-based images as needed and possibly quite often, and this inability to remove textures once loaded is completely killing my memory footprint!

    Thanks,
    - Corey
     
    KwahuNashoba likes this.
  2. RenoRosco

    RenoRosco

    Joined:
    Dec 16, 2008
    Posts:
    67
    I encountered the same problem while loading some localized textures for our game. If we switched the textures often we get an crash.
    I resolved the problem by setting the not need textures to null. You should be sure that you dont use the texture anymore. Then call
    Code (csharp):
    1.  
    2. Application.GarbageCollectUnusedAssets();  
    3.  
    that will free your memory of the unused textures. After that we load the new textures in.
    How you manage the transition between the screens is up to you. We show a small loading icon that does the job well.
     
  3. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    Thanks, Reno

    Question though: I pretty sure that I've already done that (although now I'll go back and make sure that I'm really releasing everything.) When you've done with your GC collection, are you able to see the memory release in Activity Manager (or via some other method)?

    When watching my app's memory in Instrument's Activity Monitor, I never see a corresponding memory drop after I null out textures and do GC collection.
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    the gc will never drop to null or even drop significantly.
    It will remain stable unless some other process requests memory so it has to drop its unused pool.

    thats standard gc behavior.
     
  5. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    Okay, I'm not so sure I understand about the GC and what it's supposed to be doing, so here's my not-so-hypothetical situation. Can someone please let me know what I should be seeing if I did everything right?

    • 1: Memory (as measured in Activity Monitor) starts off at 30mb.

      2: I load in some uncompressed textures off of the iPhone's document directory

      3: Memory spikes up to about 34 mb (as expected with the image load-in)

      4: I'm done with the images, I "close" the images down by taking them out of the scene and I null the texture variables that I loaded the step 2 images into.

      5:My memory doesn't change. I'm still at around 34mb. (What I'm seeing now.)
    So after step 4, should I see the memory go down, or is the current behavior (step 5) what I should be expecting to see. For my app, a repeat of 1-4 continues to push memory up and up, so I think that the textures are, in reality, not being released from memory.

    If I should see total memory drop after step 4, then that means I just missed something somewhere though, and that's a lot easier to fix (I hope...)
     
  6. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    Just to write a follow-up on this:

    I managed to find something out which may be of use to others. Ultimately, the issue was that even though I was destroying objects that referenced dynamically added texture2D objects (heavy ones, at that), the memory used by those texture2D's wasn't being returned after the parent object's destruction. I tried destroying all of the objects that made use of the texture's, destroyed the texture variables themselves, and still was never able to recapture the memory.

    So the latest thing I tried was to do the following: Once all of the objects that would were using the textures were safely destroyed (but the texture's were still there) I did a global FindObjectsOfType for Texture2D. There, I found my unassigned but still sucking down memory textures, destroyed them, and got my memory back!

    I'm not sure if that the texture2D's not releasing memory without being explicitly destroyed is a bug or not, or just an issue of my bad coding (or if it's still present in 1.6), but should anyone else run into this issue, your best bet appears to be to explicitly root out and destroy those textures after you're sure you're done using them!
     
  7. Barbur

    Barbur

    Joined:
    Oct 30, 2009
    Posts:
    160
    Hello! I am having this exact problem. I go from a level to the main menu and some textures are not being released and they are the ones that were owned by GO created dinamically. I am trying to destroy them with the Destroy function before loading a new level but I get the following error: Destroying assets is not permitted to avoid data loss....

    How did you exactly eliminated the textures from memory?

    Thanks! :)
     
  8. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    I did a find for all objects of type Texture2D, then :

    Destroy( myTexture2DObject )

    (I did a small bit of filtering to make sure I didn't remove the ones I wanted to keep.
     
  9. Barbur

    Barbur

    Joined:
    Oct 30, 2009
    Posts:
    160
    Why is this not working for me? I get that damn error! :O When you do a FindObjectsOfTypeAll are you retrieving all the objects already loaded in memory?
     
  10. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    What I do is first destroy any objects that are using the Texture2D's, then I do my Texture2D destroy.

    Not destroying the objects referencing the Texture2D's before you kill the Texture2D's may be what you're missing, and causing your error perhaps?
     
  11. Rj

    Rj

    Joined:
    Apr 21, 2010
    Posts:
    3
    Hi Redd, we seem to be experiencing exactly this issue but are having trouble following your advice.

    You mention using FindObjectsOfType and then filtering the results slightly... how did you go about this? I can't get FindObjectsOfType to return a list of textures (and the documentation does specifically say that it won't), while FindObjectsOfTypeAll lists everything that's in the project and trying to destroy these objects results in the same error that Barbur is reporting.

    Any assistance you could provide would be appreciated but it would be great if you could show us exactly what you're doing.

    Rj
     
  12. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    Here's the code I use:

    cubeToDestroy is a little options cube thing that spins around showing app options, screenshots, etc.. That options cube has a bunch of large textures imported from the iphone file system, and essentially sucks your memory down completely.

    When I go to remove the options cube, I pass a reference to it to my main app script handler, destroy it (make sure it's destroyed) then remove any textures still floating around in memory that that cube was using.

    Unfortunately this may not help you much, but my filtering is by size. All of the texture's I'm loading in on that cube are of known sizes (480,240,120), so I'm able to filter for size and remove just those textures.

    Finally, the gc collect and nulling out the cube may just be voodoo; not sure if it actually does much (but it made me feel "more secure" about removing it from memory for once and for all!)

    Code (csharp):
    1. if (cubeToDestroy) {
    2.         Destroy( cubeToDestroy );
    3.         cubeToDestroy = new GameObject();
    4.     }
    5.        
    6.     System.GC.Collect();
    7.     cubeToDestroy = null;
    8.  
    9.      var ob = FindObjectsOfType (Texture2D);
    10.      for (var t : Texture2D in ob) {
    11.         if (t.width == 480 || t.width == 240 || t.width == 120) {
    12.              Destroy(t);
    13.          }
    14.     }
    15.  
     
  13. Rj

    Rj

    Joined:
    Apr 21, 2010
    Posts:
    3
    Thanks for that Redd,

    We are running essentially the same code, we're just seeing completely different behaviour.

    On one occasion we did see a texture using this method and we were able to kill it off and successfully reduce memory usage. However, we know that we're loading quite a few textures from resources and that they are in memory... but not showing up in this list.

    Very odd.
     
  14. redd

    redd

    Joined:
    Jul 23, 2009
    Posts:
    122
    Something else to consider then: I'm very specific about setting textures I want to destroy as Texture2D; textures that I don't mind leaving in memory I set as Texture. Perhaps some of your unfindable textures are Textures, and not Texture2D's?
     
  15. Rj

    Rj

    Joined:
    Apr 21, 2010
    Posts:
    3
    For future readers, there are a couple of other points to note:
    • 1. This method will only show textures that are dynamically created from raw data; textures created using Resource.Load will not be included.

      2. From our experience, behaviour is different on the device versus in the editor (it will work on the device).
     
    ow3n likes this.
  16. minevr

    minevr

    Joined:
    Mar 4, 2008
    Posts:
    1,018
    var texa : Texture2D;

    texa =Res.Load("texfile1");
    texa =Res.Load("texfile2");
    texa =Res.Load("texfile3");
    texa =Res.Load("texfile4");

    How to release memory?
     
  17. firas darwiche

    firas darwiche

    Joined:
    Oct 4, 2006
    Posts:
    130
    set all references to the tex to null then call: Resources.UnloadUnusedAssets();
     
  18. Mgayar

    Mgayar

    Joined:
    Nov 9, 2014
    Posts:
    2
    For my case, calling that helped: Resources.UnloadUnusedAssets();
     
    Fenikkel, Naktrem and Protozoaire like this.
  19. unicoea

    unicoea

    Joined:
    Feb 18, 2013
    Posts:
    60
    Texture2D abc;
    Destroy(abc) will release the memory.
     
    samuelmorais likes this.