Search Unity

Garbage collection not happening?

Discussion in 'Web' started by monark, Sep 6, 2017.

  1. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    I have an issue in a WebGL player where the memory goes up and up when I load images into it.
    Each time I load a new one it doesn't look like the memory for the old one gets removed.
    When I look in the profiler I see lots of textures with no references, they are just blank.
    I would have thought in those cases the GC would kick in and remove them.

    Am I reading this correctly?
    Do I need to be doing something myself to actively clear this memory?

    Unity 5.6.3

     
  2. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    So it seems there are a lot of threads about this sort of thing with various answers using things like Destroy, UnloadUnusedAssets and GC.collect

    I thought this was all handled for you but seemingly not...
     
  3. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    I'm reading that you shouldn't use www.texture but LoadImageIntoTexture instead as www.texture leaks memory. Is this still the case?
     
  4. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    So it seems UnloadUnusedAssets works in the Editor but not in a WebGL build....
     
  5. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    Perhaps the WWW object is not disposed properly.
     
    Last edited: Sep 9, 2017
  6. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    So are you saying there is no way to use WWW to load textures in WebGL and not get a memory leak?
     
  7. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    What I am saying is that maybe the memory is not released because the www object is not disposed. Are you keeping a reference to the www object. Do you ever Dispose it?
    Does it work on another platform (not the editor) ?

    Perhaps if you could provide more details / a code snippet, it would be easier to diagnose the problem.
     
  8. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    I was just setting it to null, which seemed to work in the editor, I now read that maybe Dispose is needed too, so I'm trying that as well now.
    If I don't get anywhere I'll post some code or send a repro.
    I'm basically using a download manager to get a series of textures (user picks which one) and then assigning that to a GUI element to display. The question is how to properly free up all the memory when they choose a new one.
    It seems from more reading that I might need to track a bit more carefully in WebGL how the texture2d instances are managed and disposed of but it's hard to find clear information all in one place about the best methods to do this.

    So far I'm getting the idea that when using WWW you want to use dispose on it after using it.
    For Texture2D you want to Destroy it if you can when it's no longer in use
    Maybe use LoadIntoTexture and not rely on www.texture itself
    And then for clean up call UnloadUnusedAssets (which itself calls GC.collect)

    Anything else that needs to be concidered?

    I had a similar issue in the past and ended up using Resize rather than creating new and then re loading data into the resized texture. Maybe that is still a method worth using.
     
  9. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    So I seem to have dramatically improved the situation in WebGL though I can still use up all the memory after a much longer sequence of downloading and replacing textures. So I think there are still a few corners to clear out.
    What I'm still unsure about is what is the correct way to handle replacing a texture, resizing an existing one or destroying an existing one and creating new.

    So this is this way of doing it
    Code (CSharp):
    1. private void updateDisplay(Texture2D image) {
    2.         Color[] cols = image.GetPixels();
    3.         if (_displayImage != null) _displayImage.Resize(image.height, image.width, image.format, false);
    4.         _displayImage = new Texture2D(image.width, image.height, image.format, false);
    5.         _displayImage.SetPixels(cols);
    6.         _displayImage.Apply(false);
    7.     }
    Or maybe this way
    Code (CSharp):
    1. private void updateDisplay(Texture2D image) {
    2.        Color[] cols = image.GetPixels();
    3.         if (_displayImage != null) Destroy(_displayImage);
    4.         _displayImage = new Texture2D(image.width, image.height, image.format, false);
    5.        _displayImage.SetPixels(cols);
    6.        _displayImage.Apply(false);
    7.    }
    The problem is that Destroy seems to happens after you have re-assigned the texture so it seems to clears the one you want to use. When I use that form I just get a blank texture.
    The way around it, maybe, is to use DestroyImmediate but there is a warning in the help that is a bit unclear about using that in game code.

    Is it safe to use DestroyImmediate?
    or is Resize the "correct" way to handle it?

    Resizing appears to work, but I'm not sure what happens to the memory that is not required if the new texture is smaller than the old one. Does that get cleaned up or just "lost"?

    Lots of questions that are hard to be clear about without a lot of trial and error.
    Is there any officially documented way of handling Texture2D and memory?
     
    Last edited: Sep 11, 2017
  10. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    From the help for Dispose()
    So it's odd that you need to use it when a download has completed.
    What does it do?
    And is the help wrong and you should always use it if downloading textures? or anything?
     
  11. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    sorry for the delayed reply. If you could provide a simple repro that shows the memory leak I will take a look at it.
     
  12. monark

    monark

    Joined:
    May 2, 2008
    Posts:
    1,598
    I think I have it under control now, but I still don't really know which functions are required and which aren't as the docs aren't clear. I'm just using Dispose() and UnloadUnusedAssets() whenever I load anything from www, and Destroy where I can.
    It would be great if the docs could contain an example of the best practice for this.