Search Unity

Unity Memory leaks problem

Discussion in 'Editor & General Support' started by TheStrongSkye, Sep 17, 2018.

  1. TheStrongSkye

    TheStrongSkye

    Joined:
    Oct 29, 2016
    Posts:
    23
    Hello
    I have a problem with memory leaks, after building my game, the memory usage is raising up.
    I found some informations on Unity Profiler:

    After starting a game, Total Objects Count is rising to infinity :O
    "Temp Buffers" causes a problem - HideFlags are set to HideAndDontSave -> Screenshot down below:


    My game is a survival game. I'm using Ultimate Water Sytem but after build, there is no water in final .exe dont know why - maybe the water causes a problem ?

    My question is how can i fix that, that memory leak?
    Thanks for help :)
     
  2. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
  3. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    And thank you for raising the question. We're currently working on the next version of the Memory profiler and within that work it's the second time this week, that the question of "what's the TempBuffer" came up, so I'll see if we can add some more meaning to it in the new UI :)
     
  4. TheStrongSkye

    TheStrongSkye

    Joined:
    Oct 29, 2016
    Posts:
    23
    When i clicked on random "TempBuffer" i saw a highlighted object on my scene - it was prefab of a simple rock.
    I found script with that "RenderTexture" parameter. I think it looks fine:
    Code (CSharp):
    1. namespace UltimateWater.Internal
    2. {
    3.     using UnityEngine;
    4.  
    5.     public struct TemporaryRenderTexture : System.IDisposable
    6.     {
    7.         #region Public Methods
    8.         public RenderTexture Texture
    9.         {
    10.             get { return _RenderTexture; }
    11.         }
    12.  
    13.         public void Dispose()
    14.         {
    15.             if (_RenderTexture == null) return;
    16.  
    17.             _Cache.ReleaseTemporaryDirect(_RenderTexture);
    18.             _RenderTexture = null;
    19.         }
    20.  
    21.         public static implicit operator RenderTexture(TemporaryRenderTexture that)
    22.         {
    23.             return that.Texture;
    24.         }
    25.         #endregion Public Methods
    26.  
    27.         #region Private Variables
    28.         private RenderTexture _RenderTexture;
    29.         private readonly RenderTexturesCache _Cache;
    30.         #endregion Private Variables
    31.  
    32.         #region Private Methods
    33.         internal TemporaryRenderTexture(RenderTexturesCache renderTexturesCache)
    34.         {
    35.             _Cache = renderTexturesCache;
    36.             _RenderTexture = renderTexturesCache.GetTemporaryDirect();
    37.         }
    38.         #endregion Private Methods
    39.     }
    40. }
    Also as you can see, in the profiler there is:
    Referenced by:
    HideAndDontSave, Manager or AssetBundle()

    I know that it's a HideFlags, I thought that i can change this parameter to stop memory leaking but i dont know what is Manager or that AssetBundle method. Any suggestions ? P.S Thanks for reply :)
     
    Last edited: Sep 18, 2018
  5. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    You're welcome :)
    The code you posted is not implementing a full Dispose pattern which means that, if the garbage collector would clean up TemporaryRenderTexture, its Finalizer would not know it needs to call Dispose and it leaks. Also, relying on the Finalizer is bad and hopefully that Dispose method would be called earlier. Have you looked at all the places where TemporaryRenderTexture is used? It should ideally only be used in a using scope. If not, at the very least Dispose needs to be called on it reliably.
     
  6. TheStrongSkye

    TheStrongSkye

    Joined:
    Oct 29, 2016
    Posts:
    23
    Dispose method is not full, so what should i edit in this script ? And what about objects like a rock/stone with no scripts ? I need to add a script to that objects manually with dispose method ? How about creating a script with RenderTexture[] ? and adding every object(texture) to this script and call Dispose method ? Could you give me some example please ? :D P.S The Unity Version I use is 2017.1.0p5
     
    Last edited: Sep 19, 2018
  7. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    For a full description of the dispose pattern, please read through this.
    In this case, I'd do something like this:

    Code (CSharp):
    1. namespace UltimateWater.Internal
    2. {
    3.     using UnityEngine;
    4.     public struct TemporaryRenderTexture : System.IDisposable
    5.     {
    6.         #region Public Methods
    7.         public RenderTexture Texture
    8.         {
    9.             get { return _RenderTexture; }
    10.         }
    11.         public void Dispose()
    12.         {
    13.             Dispose(true);
    14.             //If disposing was succesful, this instance does not need to be finalized anymore
    15.             GC.SuppressFinalize(this);
    16.         }
    17.      
    18.         public static implicit operator RenderTexture(TemporaryRenderTexture that)
    19.         {
    20.             return that.Texture;
    21.         }
    22.         #endregion Public Methods
    23.         protected void Dispose(bool disposing)
    24.         {
    25.             if(disposing || !disposed)
    26.             {
    27.                 if (_RenderTexture == null) return;
    28.    
    29.                 _Cache.ReleaseTemporaryDirect(_RenderTexture);
    30.                 _RenderTexture = null;
    31.                 disposed = true;
    32.             }
    33.         }
    34.      
    35.         #region Private Variables
    36.         private bool disposed;
    37.         private RenderTexture _RenderTexture;
    38.         private readonly RenderTexturesCache _Cache;
    39.         #endregion Private Variables
    40.         #region Private Methods
    41.         internal TemporaryRenderTexture(RenderTexturesCache renderTexturesCache)
    42.         {
    43.             _Cache = renderTexturesCache;
    44.             _RenderTexture = renderTexturesCache.GetTemporaryDirect();
    45.         }
    46.      
    47.         // The Finalizer only gets called when an instance of this class was not succesfully disposed before it got Garbage Collected
    48.         ~TemporaryRenderTexture()
    49.         {
    50.             Dispose(false);
    51.         }
    52.         #endregion Private Methods
    53.     }
    54. }
    While doing that, I realized it has a RenderTexturesCache, that is not a class defined by unity so it likely is part of UltimateWater as well. I'm hoping that this cache is not leaking either and that
    _Cache.ReleaseTemporaryDirect(_RenderTexture);
    just calls
    Code (CSharp):
    1. RenderTexture.ReleaseTemporary(_RenderTexture)
    .

    RenderTextures are not your normal Textures so for rocks and similar that are not using this script, you don't need to do anything. If you're using an IDE like Visual Studio or Monodevelop, you can use that IDE to find all references to TemporaryRenderTexture (or RenderTexturesCache?) and check that everywhere it is used, Dispose is called on it.
     
    Last edited: Sep 20, 2018
  8. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    Regarding:
    You can't change the HideFlags for RenderTextures. They are created in native code, the HideFlag keeps them from getting unloaded by UnloadUnusedAssets and they need to be cleaned up manually, which is what this Dispose pattern is supposed to ensure.
     
  9. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    actually, above Dispose pattern implementation is bad, because it could call
    _Cache.ReleaseTemporaryDirect(_RenderTexture);
    during finalization when the _Cache might already have been finalized. The order in which objects get finalized is not defined so that should be:
    Code (CSharp):
    1.  
    2.         protected void Dispose(bool disposing)
    3.         {
    4.             if(disposing)
    5.             {
    6.                 if (_RenderTexture == null) return;
    7.    
    8.                 _Cache.ReleaseTemporaryDirect(_RenderTexture);
    9.                 _RenderTexture = null;
    10.                 disposed = true;
    11.             }
    12.             else if(!disposed)
    13.             {
    14.                 if (_RenderTexture == null) return;
    15.                 RenderTexture.ReleaseTemporary(_RenderTexture);
    16.                 _RenderTexture = null;
    17.                 disposed = true;
    18.             }
    19.         }
    Then again, I have no idea what RenderTexturesCache looks like.

    also, you might want to read through this thread. Maybe there's something in there or maybe you can raise the question there as well with others who know the system and have access to the code.
     
  10. TheStrongSkye

    TheStrongSkye

    Joined:
    Oct 29, 2016
    Posts:
    23
    Meanwhile I've moved project to newest version (at the moment) so I am working on 2018.2.8 now. I've replaced code of that script to code you gave me, then i've got error about destructor at the end (i've changed
    public struct TemporaryRenderTexture : System.IDisposable
    to
    public class TemporaryRenderTexture : System.IDisposable
    and it worked) I found 17 references of "TemporaryRenderTexture" so I've added
    System.GC.SuppressFinalize(this);
    to all Dispose methods I found, then i profiled a game (build) and nothing changed. TempBuffer is still leaking :/ Any suggestions ?
     
  11. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    2,460
    Adding the finalizer won't fix it looking like a leak. You'll still generate TempBuffers untill GC.Collect is triggered and they are freed. The real fix is to make sure Dispose is called on them at all. So for all those 17 instances check that Dispose is called. If possible, decide and conquer. Meaning, reduce the occurrence of things that use TemporaryRenderTexture in your scene to one half of it and see if it still leaks. If no, try the other half. If yes, half again.

    Additionally, it'd be good if you could share the code of RenderTexturesCache.
     
  12. TheStrongSkye

    TheStrongSkye

    Joined:
    Oct 29, 2016
    Posts:
    23
    Breaking News: I made a scene without a water and there is no memory leak :O My Ultimate Water System version is 2.1.0 - I Should download hotfix but i am using it for educational purposes only it means that i dont bought that. I am pretty sure that hotfix will fix that but atm i cant download it so Thank you for your time and help ;)
    P.S If the problem will still exist after hotfix I will ask you ;) Regards
     
    MartinTilo likes this.