SharpDX crashing the app after having resumed a few times?

Hello everybody!

I’ve been banging my head against a wall with a hard to trace bug for a while. Would you maybe have some good insight on what I’m doing wrong?

Me and my co-workers have ported a game from XNA to MonoGame for the Windows Phone 8 but we run into problems when resuming the app too many times in a row. The resume is quite slow and then after about 4 to 6 times the app crashes.

Sometimes it seems like it might be running out of memory but then more often the stack trace points to a SharpDXException with a message “The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action.”

Our XNA version for the Windows Phone 7 resumes and runs without problems.

This might be related to an earlier bug we had. Some of our spritesheets disappeard when the app resumed so I tried adding a function that reloads them on resume. But with ContentManager they should only get reloaded when they’ve been unloaded, right? Or would that cause unnecessary memory buildup?

Have you ever ran into the same problem and would you have any idea of how to work around this? I would love to get this sorted since this is a must fix thing for us. I like my job, I want to keep it :slight_smile:

Thank you in advance!

EDIT: This seems to be a memory management issue in my code. If you have any tips about memory management with MonoGame I’d be happy to hear them! Thanks!

Yes, I can confirm it seem to be a memory leak. Coming from the same team as “Ihmelaama” I just ran some tests, it looks like that app memory usage (ApplicationMemoryUsage) grows between resumes, until it hits the limit (ApplicationMemoryUsageLimit).

Since the latest (2.6) release of SharpDX fixes some memory issues (e.g. this :https://github.com/sharpdx/SharpDX/commit/3ee777787d8f3b86e242e1614e0ab0529b017a71), we would like to try it out with Monogame. Obviously simply replacing SharpDX dll:s doesn’t work. Any ideas how to install it on Monogame?

EDIT: Tried out SharpDX 2.6.2, no luck… :frowning:

There is a memory leak for sure - somewhere. Here’s a code that just loads a 4MB texture and then sits still. Switching back and forth between the app and OS (e.g. pressing Windows and back buttons) shows that the app eats gradually more and more memory (megabytes) in every turn.

If you guys have ANY ideas, please let us know. We have a game to be published soon and this is a major issue for us with 512MB devices, e.g. popular Lumia 520.

using System; using System.Linq; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Phone.BackgroundAudio; using System.Diagnostics; using System.Text; using System.Threading.Tasks; using System.Windows;

namespace MonoGameSample
{
    public class Game1 : Game
    {
        const int TEXT_NUM = 10;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D testTexture;

protected override void OnDeactivated(object sender, EventArgs args)
        {
            System.Diagnostics.Debug.WriteLine("");
            System.Diagnostics.Debug.WriteLine(“ON DEACTIVATED”);
            System.Diagnostics.Debug.WriteLine("DeviceTotalMemory: " + Microsoft.Phone.Info.DeviceStatus.DeviceTotalMemory);
            System.Diagnostics.Debug.WriteLine("ApplicationCurrentMemoryUsage: " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage);
            System.Diagnostics.Debug.WriteLine("ApplicationMemoryUsageLimit: " + Microsoft.Phone.Info.DeviceStatus.ApplicationMemoryUsageLimit);
        }

protected override void OnActivated(object sender, EventArgs args)
        {
            System.Diagnostics.Debug.WriteLine("");
            System.Diagnostics.Debug.WriteLine(“ON ACTIVATED”);
            System.Diagnostics.Debug.WriteLine("DeviceTotalMemory: " + Microsoft.Phone.Info.DeviceStatus.DeviceTotalMemory);
            System.Diagnostics.Debug.WriteLine("ApplicationCurrentMemoryUsage: " + Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage);
            System.Diagnostics.Debug.WriteLine("ApplicationMemoryUsageLimit: " + Microsoft.Phone.Info.DeviceStatus.ApplicationMemoryUsageLimit);
        }

public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = “Content”;
        }

protected override void Initialize()
        {
            TouchPanel.EnabledGestures = GestureType.Tap;

base.Initialize();
        }

protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            testTexture = Content.Load(“test_texture”);
            base.LoadContent();
        }

protected override void UnloadContent()
        {
            base.UnloadContent();
        }

protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

base.Update(gameTime);
        }

protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();
            spriteBatch.End();

base.Draw(gameTime);
        }
    }
}

Maybe related https://github.com/mono/MonoGame/issues/1771

Yep, that is probably related.

Anyway, workaround seem to be to call Content.Unload (or Content.Dispose) in OnDeactivated. Obviously you need to load everything back when resume. Need to test more…

EDIT: Content.Unload and Content.Dispose seem to be a no-go. They don’t consume more memory, but they don’t free it up properly either. After resume you are forced to reload content and we face the same issue again - more and more memory is consumed after every resume. Bummer, I’m running out of options here… :frowning:

Thanks, daveleaver! I think you might be right, this could be the issue.
This might be related too: https://monogame.codeplex.com/discussions/395896

Maybe a threaded content load could be a solution in our case.
I’m too much of a n00b to know how to do it though. :frowning:

There’s now $100 bounty available for fixing this:

Ville, I tested with threads too. Created own content mgr in a separate thread. In OnDeactivated told thread to dispose texture and content, then killed the thread. When back after resume, recreated the thread and asked it to load texture again. No luck. I didn’t even draw the texture, just loaded it with content manager. 4BM memory (texture size) wasted in every resume.

Is there any alternative content manager available somewhere?

Update for those who may be interested. We ended up with this workaround:

  1. Reduced the active content size to minimum, using spritesheets with compression and loading compressed sound FX only when needed
  2. Disposing content manager and forcing carbage collection with GC.Collect in OnDeactivated routine
  3. Recreating content manager and reloading content in OnActivated

Not the most sophisticated resolution, but it works and doesn’t crash low end WP phones anymore. Available memory still wanders between resumes in a peculiar way, but it eventually stays below the limit.

I hope the root cause gets resolved one day. My guess is a memory leak either in Monogame or SharpDX, ie poor ContentManager memory handling in hold/resume situations.

I am also seeing this behavior. Unfortunately your workaround does not seem to have solved my problem. The memory usage still wanders upwards, albeit slower than before.

Hello all,

can you please test this branch?

Another pull request sync with latest changes in /develop.