Hi all,
I’ve past experience of XNA, and we currently have internally our app running using Monogame + Xamarin on OSX, iOS, Android and PC. We are only having the memory issue on the PC.
I’ve been tracking a memory issue we have had just on the PC, and I can now replicate it in a few lines of code in a sample project.
Win10 + VS 2015 Enterprise + Monogame 3.4, or latest development build from the build server give me the same results.
My test case is now just this, use the VS template for a Windows Project, and pop the following code into LoadContent:
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
var ms =
new MemoryStream(
File.ReadAllBytes(
@"c:\temp\monogame\monogameWin10\monogameWin10\monogameWin10\bin\WindowsUAP\x86\Debug\AppX\tile.png"));
for (int i = 0; i < 200000; i++)
{
ms.Seek(0, SeekOrigin.Begin);
var tex1 = Texture2D.FromStream(graphics.GraphicsDevice, ms);
tex1.Dispose();
}
// TODO: use this.Content to load your game content here
}
The PNG is just a 260*260 pixel image.
We load maps from file - we have GB’s of data with customers, hence we do it using FromStream. It would appear its FromStream that isn’t freeing memory somewhere.
Start the above code up, memory quickly hits about 50mb, sits there for a minute or so, and then climbs very quickly into the GBs. If I run the new UAP template in the same way, the result is very similar.
If I run the same trivial code in the same way but using the Visual Studio OpenGL template, the code runs fine, with no memory issues.
Ways forward:
- Someone please tell me I’m a Muppet, and tell me what is wrong with the above code?
- I’m happy to try to track this, but I’m having an issue in compiling the code from GitHub - I’ve posted on a different thread about that.
Otherwise, I’ve worked out a way to create just a grid of textures at startup, and then use SetData:
var texturebytesNew = new byte[260 * 260 * 4];
var tex = new Texture2D(GraphicsDevice, 260, 260);
var bytes = new byte[260 * 260 * 4];
for (int i = 0; i < 200000; i++)
{
ms.Seek(0, SeekOrigin.Begin);
using (var tBitmap = new Bitmap(ms, false))
{
var data = tBitmap.LockBits(new System.Drawing.Rectangle(0, 0, tBitmap.Width, tBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
tBitmap.UnlockBits(data);
for (var oy = 0; oy < tBitmap.Height; oy++)
for (var ox = 0; ox < tBitmap.Width; ox++)
{
texturebytesNew[oy * (260 * 4) + ox * 4] = bytes[oy * tBitmap.Width * 4 + ox * 4 + 2];
texturebytesNew[oy * (260 * 4) + ox * 4 + 1] = bytes[oy * tBitmap.Width * 4 + ox * 4 + 1];
texturebytesNew[oy * (260 * 4) + ox * 4 + 2] = bytes[oy * tBitmap.Width * 4 + ox * 4 + 0];
texturebytesNew[oy * (260 * 4) + ox * 4 + 3] = bytes[oy * tBitmap.Width * 4 + ox * 4 + 3];
}
}
tex.SetData(texturebytesNew);
}
It works, but it’s certainly slower. Again, memory usage based on SharpDX climbs but they stays fairly static. OpenGL just uses a lot less memory, and seems much more static.
I’d rather not move to OpenGL, as I would like to move on the new MS Universal Apps, and I believe they rely on DirectX. Our app is also displaying its output into a WPF window, and I’m sure there must be a solution for it from OpenGL, but it wasn’t an obvious alteration to our current code.
Many thanks for the great work here, and hoping someone can point me in the right direction/help.
Kind Regards,
Graham