Huge problem with memory accumulation. 'Dispose' and 'Unload' aren't working

I’m having a huge problem with memory accumulation in all my games.
This happened after switching from monogame 3.4 to 3.5 so I switched back.
Then recently I went to 3.6(latest release) and started having the same problem again.
I would switch back again but I need 3.6 rather than 3.4 for certain reasons.

I’ve tried both .Dispose() and .Unload() for the content but it seems to only release a small portion of what was previously loaded.

Here is the code

  public void UnloadContent()
        {
            if (overworldContent != null)
            {
                overworldContent.Unload();
            }
        }

I’ve also done

 public void UnloadContent()
        {
            if (overworldContent != null)
            {
                overworldContent.Dispose();
            }
        }

This is a picture of the memory usage from just going in and out of an area just a few times over the course of several minutes.
A player could easily have multiple gigabytes taken up from playing for even just one hour if it goes from 86MB to 235MB in just 2 minutes

I seriously need help.

Do you use multiple ContentManagers and keep them alive? MG uses a scratchbuffer for each content manager that grows as large as your largest texture. Related issue: https://github.com/MonoGame/MonoGame/issues/5341

Yes I’m using multiple ContentManagers.
Is that a problem?
If so then how do I properly free memory used up by assets that are currently not in use?

The details are in the issue I linked, but basically you should allow the ContentManagers that you’re not using to be garbage collected. I have a pull request up that should fix this issue, you can test it if you’d like.

1 Like

I have no idea how to use your code, what a ByteBufferPool even is, or where to find the NUnit.dll.

I added the ByteBufferPool class to my project but I don’t know how to use it.

Could you give me more specific instructions?

This is my code for loading content if it helps.

  public void LoadContent(ContentManager originCManager, GraphicsDeviceManager originGManager, GraphicsDevice originGraphicsDevice, MainGameClass newMainClassInstance)
    {
        graphics = originGManager;
        graphicsDevice = originGraphicsDevice;
        currentMainClassInstance = newMainClassInstance;
        overworldContent = new ContentManager(originCManager.ServiceProvider, originCManager.RootDirectory);

        btnA = overworldContent.Load<Texture2D>("Images/UI/btnA");
        backgound = overworldContent.Load<Texture2D>("Images/Backgrounds/Tharsis Labeled (No Key)");
        plyrSpriteSheet = overworldContent.Load<Texture2D>("Images/Characters/playerSpriteSheet");

        standardFont = overworldContent.Load<SpriteFont>("Fonts/standardFont");

        plyrPos = new Vector2(150, 150);//starting position of player
        plyrAnimation = new animate(plyrSpriteSheet, new Point(90, 144), new Point(4, 8));
    }

You don’t have to understand the code, but to test it you should build from source. Here’s a step-by-step guide to clone MG and try my branch:

  1. Install Git if you don’t have it yet.
  2. Open a terminal (Linux/Mac) or Git Bash (Windows)
  3. Navigate to a location where you want to clone the MG repository.
  4. Clone the MG repo by running git clone https://github.com/MonoGame/MonoGame.git in the terminal
  5. Navigate into the MonoGame directory: cd MonoGame
  6. Clone the submodules: git submodule update --init
  7. Add my repo as a remote: git remote add jjagg https://github.com/Jjagg/MonoGame.git
  8. Fetch my branch: git fetch jjagg scratchpool
  9. Check out my branch: git checkout scratchpool
  10. Run Protobuild to generate the project files: Protobuild.exe or mono Protobuild.exe on Linux/Mac
  11. Replace the reference to MG in your game with a reference to the generated project.
    For VS:
  • Click Add > Existing Project… on your solution and select the MonoGame.Framework project that matches the template (e.g. MonoGame.Framework.Windows.csproj for a MonoGame Windows project template)
  • In your game project remove the MonoGame.Framework reference.
  • In your game project click Add Reference… > Projects and selected the MG project you just added.

Dispose() (which Unload() calls internally) will make sure the unmanaged resources are released. You still need to make sure that all managed resources are released so the garbage collector can clean up the objects.

You would be best served by using a memory profiler to confirm what objects are still holding references to objects that are preventing those objects from being garbage collected.

1 Like

Thanks for trying to help me out Jjagg. After coding for nearly 12 hours (most of which was troubleshooting this issue), trying to then figure out that git stuff was super frustrating. I went back to my project to try a few last things and I think I’ve figured it out. Instead of using just Unload() or Dispose() using both at once seems to work a lot better. I’ve also noticed that if I also set the ContentManager to null it will clear the memory even faster. My code looks like this now.

    if (overworldContent != null)
    {
        overworldContent.Unload();
        overworldContent.Dispose();
        overworldContent = null;
    }

Apparently after using Unload() it will still keep some junk in a scratchbuffer (whatever that is) and using the other method along with nullifying the ContentManager for that class will ensure that the rest gets cleared out.

1 Like