I’m using the amazing asset “Graphy” to monitor my performances in-game. There is 3 things to watch as far as memory is concerned.
Reserved
Allocated
Mono
While my Reserved and Allocated values are all fine over the course of the runtime session, my Mono keeps going up, sometimes clearing a couble MB, but not enough to go back down to what it was when the game opened.
This makes me think I have a memory leak or a problem with Garbage Collection in my project.
What are the steps you would recommend for me to find the culprit? Where should I start? What would you do?
I have to be honest, I have taken snapshots in the memory profiler, but I don’t really understand how to analyze them.
Beyond that you should probably dig deeper than these high-level numbers using the Memory Profiler Package (which hasmayor UI UX overhaul pending which should make this all easier to gorg) or the HeapExplorer .
I should’ve mentionned, I’m on 2019.4 (LTS). I’ll dig in and try to show more details as to what could cause memory to constantly increase. Heap Explorer seems nice!
Reading the page you linked for GetMonoUsedSizeLong, I noticed the following:
“Note that this will return an ever increasing value until GC.Collect() is called.”
I enabled the incremental GC in my project, maybe I shouldn’t have?
That looks like a Transform named Group which probably has quite a few child elements?
I’d start by looking at the biggest items there though. It’s quite some textures and a somewhat odd total of 2d int32 arrays ( int32 [,]) and other multidimensional arrays, which would more directly tie to the mono memory growing, unless all hose textures re basically just managed shell objects without a native object underneath them.
The Profiler Window’s detailed snapshot does not capture any details of the Managed Heap. To see those details you have to use the Memory Profiler Package. In there, if you want to focus on the Managed Heap, you can select the view: Tables > All Managed objects.
As per your previous screenshot, it looks like it might be down to quite a few multidimensional arrays. Check if all of those need to be in memory, who is referencing them and if that all looks correct to you.
Here, I have 1300-something references to each terrain texture, and it’s referenced by objects that have nothing to do with it and no reference to either a terrain, or a texture, in its code. Why is my “OBK_Destructible” component mentionned in the “referenced by” tab referencing to a terrain texture? It is absolutely black magic for me. Doesn’t make any sense.
Now I still am trying to use the memory profiler. I went to “All managed objects” and sorted them using filters according to what you said in your previous post (I don’t know what I’m looking for though, so pretty hard to even know if I’m looking at the right place).
No worries, the UI is really suboptimal and something I have to apologize for. Have you tried clicking the Type column and searching for the classes of your multidimensional arrays? Also, you can click on that RefCount in there to see the connections there, even if only one layer at a time instead of as a tree as in the right column of the memory Profiler module.
Also 107 Render Textures sounds like a bit unusually high unless you are doing something unusual with them I guess?
If your memory usage count is continuously rising, try taking two snapshots in quick succession (but enough time passing for the numbers to rise) then open both snapshots and diff them. In the diff mode, check the All Managed Objects table and group the Diff column and check the new objects. Chances are whatever you are leaking is something you are continuously creating anew and not loosing all references to them afterwards.
You also have some Texture2D Objects without a name, so if you are creating new textures from code, make sure to assign a helpful value to their .name field to make tracking them easier.
Do you have any Texture2D Objects in the Managed Objects table that have m_CachedPtr = 0? That would indicate leaked managed shell objects, i.e. you called Destroy() on them, deleting the native texture memory, but are still holding a reference to their scripting reference wrapper. Might be some references need to be set to null? Their blue RefCount link text should be clickable and tell you what is holding on to them.
Click on the blue 1 in the RefCount column. That should show you what is holding the reference to this empty managed shell, and therefore point to the culprit of the leak.
Keep in mind that empty managed shell objects appear as fake null because UnityEngine.Object overrides == operator and implicit cast to bool to show that it the Object is null or false respectively, when it is only an Empty shell that had it’s native part Destroyed.
Thanks for your help, it’s very much appreciated. My case is very hard to deal with so I’m gonna give some more details on what’s going on.
I’m not sure if it’s normal to see this, but when I’m not moving, my “mono” (using graphy for real time stats) is constantly going up but it goes back down every now and then, so it actually never really stack memory, it looks like it’s doing garbage collection after a couple seconds, which brings it down to what it was, or close to it. So unless you tell me it should be absolutely stable, I don’t think it’s a problem. That’s also why comparing snapshots can be very misleading.
My problem is when streaming new scenes, aka when my player moves around the world, something is not unloading from the unloaded scenes. What would you suggest to find out what’s keeping stuff in memory? I have dozens of scenes being unloaded and loaded when I move in the world, so I need to find a way to see an unloaded object still in memory.