ContentManger Not Unloading Properly

Hey everyone,

I have two ContentManagers, one that contains assets that are always in memory, and another that unloads between levels. Whenever I call Unload I see a small amount of memory unload, but no where near the amount that it should be. (For example: I load in ~600mb of content but only 100 is leaving memory) So because of this my game crashes because there’s no more memory on the Xbox One for the next level. I’ve also tried calling Dispose on the ContentManager, and manually calling GC.Collect but the results are the same.

When my game boots, I’ve tested loading both level one and two, and they both load fine individually… so I know the issue isn’t that one of the levels has too much content. The out of memory exception only happens when I load level one, unload and then try to load the next level.

This issue only seems to occur on UWP… this code works correctly on MonoGame.PS4 and XNA4. I’ve read other topics where people have had this issue but so far I haven’t found a solution. Are we supposed to call Dispose on every single object individually? I was under the impression we only need to call Unload on the ContentManager that loads in the content.

Would really appreciate some help!

Hey @michaelarts!

I think this might be the same issue as reported here: https://github.com/MonoGame/MonoGame/issues/5341
In short, the ContentManagers use a big persistent buffer to load assets into so they don’t have to allocate memory again every time. That memory will stay allocated as long as you keep a reference to the ContentManager. Are you loading any really large graphics assets by any chance? The buffer grows as large as the largest loaded asset that makes use of it.

Not sure why you don’t have the issue on PS4 though. Did you profile it or just did not run out of memory?

Hey thanks for the link and quick reply! Yes, my game is very graphic heavy so I imagine this is the issue. Looks like I’ll have to set the content manager to null, call garbage collect and then create a new one.

I didn’t profile the PS4, but no it doesn’t crash there. Maybe what I’m running into is that the Xbox One restricts memory for UWP titles… however I thought we had 4GB and that should be plenty for my title =-/

I’m not sure about UWP limits on XBone. Forcing to collect the ContentManager is a good short-term workaround. I have an open pull request that makes ContentManagers pool their buffers so only 1 should be allocated at once unless you load in parallel. I’ll post back here once it’s merged if I remember. Good luck with the game! :wink:

Out of memory exception is ussally kicked all the way back from the card.
Which indicates that some thing is not being disposed of … properly.
So the card is basically filling up with memory.
When i say properly i mean it could be on your side or monogames side or both.
It’s tricky stuff and when it comes to the card it gets even trickier.

You can check if objects are disposed as well after you call collect(true), IDisposable implements a IsDisposed method meaning after you unload you can test each content object for being null and or isdisposed to try to track down problems. Though neither will tell you if it’s been finalized.

You should definately call
Collect(True);
True ensures that the gc waits for the trace to complete before returning control of the thread.

Or try calling it twice, there are reasons this might work.
Collect(true);
Collect(true);

You can try to call the below, though this is not a good sign if it works,

Collect(true);
GC.WaitForPendingFinalizers();
//Then another
Collect(true);

If this works it might indicate that a dispose method isn’t set up right.
Thier is no guarentee that this will work GC.WaitForPendingFinalizers() if it works.

Thanks everyone, I tried putting true into the GC.Collect but the results were the same.

My workaround right now is to DXTCompress all my textures, and then when unloading the level content I call Dispose, set the ContentManger to null and call GC.Collect();. I can get my game running like this, though I’m not happy with how the textures look…

It still strikes me as something isn’t quite right here. The fact that all of the levels load fine by themselves is what makes me think there’s some other issue. For now I might have to suck it up and make do, as I need to get my game into certification soon.

This by itself did not help? Maybe with a memory profiler (on desktop) you can see what’s taking up so much space.

Unfortunately, no it didn’t. Though it did help in combination with the other things I did! What’s a good memory profiler you recommend?

People here often recommend the one built into Visual Studio, but I haven’t used it much.

Ok I’ve used it… and now I’m not sure this is a memory issue at all… after implementing the ContentManager work around you suggested, it definitely is unloading the correct amount of memory.

I’m now getting some weird results. Sometimes my second level loads properly, other times it exits silently or crashes regarding memory. I have some questions though:

  1. Are the CPU and GPU memory shared on Xbox One? If so, this is definitely not a memory issue. I can use the MemoryManager class under Windows.System to see what my memory limit is, and how much memory I’m currently using. I have a ton of memory available, yet I’m still getting crashes when loading levels.

  2. Does Windows UWP automatically terminate games that don’t call base.Update() after five seconds or so? I’m starting to think my issue is that my loading is sometimes taking too long which is causing the program to exit or crash.

You should probably read this it highlights some additional problems that can occur when dealing with disposable objects take a look at the comments as well.

https://blogs.msdn.microsoft.com/shawnhar/2006/09/06/taking-out-the-trash/

https://blogs.msdn.microsoft.com/shawnhar/2007/03/09/contentmanager-readasset/

Additionally people forget that the gpu is really in charge of its own memory and from its view its interaction is with the device driver.
I found in xna that i could test a lot of things not by trying to stop the oom’s.
Instead run things at the edge of forcing them to occur.
I did that by boosting up the used up memory on the gpu using load from file huge assets. Then attempting to load unload and reload things with just enough memory to know exactly when i screwed something up.

You can use something like msi afterburner as well to watch the gpu memory in real time at least on pc.

1 Like

That’s exactly what was causing the freeze on WinPhone8, CompositionTarget.Rendering event would stop firing because the event was taking too long. The standard 16.6μs step would ‘freeze’ the game within seconds. I don’t know if that’s a bug or a ‘feature’. I never seen this on Windows10/UWP but on the other hand I never hold the event for 5 minutes either.

What MG version are you using?
MG 3.6 uses the CompositionTarget.Rendering event. It’s easy to test if this is an issue by splitting the loading in two-or more steps that take less time.
Latest develop build runs it’s game loop on a separate thread, it shouldn’t be an issue on how long you keep the update.

Edit
by the way, the old bug I am referring to will freeze the gameloop , until something will wake it up, like a touch event.
it will not crash the app. Can you look for any kind of exceptions/errors happening before the crash?

Unfortunately it just silently exits… no exceptions, no output window info, nothing :frowning: Based off what you said I think this could be a problem. I’m going to do a quick hack with my loading that lets base.Update() be called and I’ll report back the results!

I’m using MG 3.6, and I pulled from the develop branch a few months ago.

Thanks everyone for the ideas, it’s definitely helping me work through this lol.

Thanks for the link, it was helpful! I’m going to hack around a little more while keeping this in mind and we’ll see what I come up with lol.

I suppose you could make a test that intentionally freezes the update and see what happens.
That would be a really weird quirk.

So quick update: to take advantage of all the Xbox resources available to games, you need to make sure your application is marked as “Game”.

More info here: https://blogs.msdn.microsoft.com/chuckw/2017/12/15/directx-and-uwp-on-xbox-one/

Doing this, in combination with the ContentManager fix mentioned earlier in this thread got me up and running.