Reducing Dynamic Memory Allocation when Rendering

I’ve recently been looking to reduce instances of dynamic memory allocation, and I noticed that my drawHUD function (which is called each frame) generates some memory with each call, which builds up over time and eventually must be garbage collected. Curious as to why, I decided to compare memory snapshots in visual studio, and I discovered that each instance of SpriteBatch.Draw is generating a small amount of memory. According to the snapshots, one call to SpriteBatch.Draw generates an additional 4 counts of “HandleCollector+HandleType”, and an additional 1 count of “SharpDX.Direct3D11.ShaderResourceView”. While I recognize that in isolation these calls are generating negligible amounts of memory, the type of game I’m working on requires a consistently smooth framerate, so I’d really like to avoid any unnecessary buildup of garbage. Is the memory generated during SpriteBatch calls unavoidable, and if so, are there any tips for minimizing memory usage in the rendering process as a whole?

EDIT: I have also just discovered that memory usage increases very rapidly while moving the mouse around over the game window, or holding a key down. A bit of research suggests that this may be due to the underlying behavior of Winforms or OpenTK. I’m seeing the same results as described in this github issue, https://github.com/MonoGame/MonoGame/issues/3662 though the issue was ultimately closed.

2 Likes

The HandleCollector+HandleType is some internal type of the GC and probably related to some other allocations.
The ShaderResourceView could be related to the Effect. Are you using SpriteBatch with a custom effect? Normally MG caches those types.

I have a fix for MouseState garbage here (6168).

1 Like

Ah, I was testing the memory via breakpoints on the very first render with a spriteBatch, so if MG caches that instance of allocation then its most likely not an issue. The MouseState fix looks like just what I was looking for, thank you!!

To close off this thread, Id like to mention a few of the things I have learned since then about minimizing the buildup of garbage when working in C# + MonoGame:

Store your model bone transforms!
At some point early in my project’s development, I needed to handle positioning models with multiple sub-meshes. I must have done a bit of research, and ended up with a solution that looked like this:

		//copy in the bone transforms from the model
		Matrix[] transforms = new Matrix[models[modelName].Bones.Count];
		models[modelName].CopyAbsoluteBoneTransformsTo(transforms);

		foreach (ModelMesh mesh in models[modelName].Meshes) {
			foreach (BasicEffect be in mesh.Effects) {
				be.Projection = camera.proj;
				be.View = camera.view;
				be.EnableDefaultLighting();
				be.World = transforms[mesh.ParentBone.Index] * world;					
			}
			mesh.Draw();
		}

Although obvious in hindsight, the call to Model.CopyAbsoluteBoneTransformsTo each frame was very quickly causing garbage to build up, and led to stuttering as the garbage collector tried to keep up. This was fixed by only copying bone transforms one time for each model:

		//copy in the bone transforms once for each model to avoid frivolous GC
		if (!modelBoneTransforms.ContainsKey(modelName)) {
			modelBoneTransforms[modelName] = new Matrix[models[modelName].Bones.Count];
			models[modelName].CopyAbsoluteBoneTransformsTo(modelBoneTransforms[modelName]);
		}

Pass a StringBuilder to SpriteBatch.DrawString
Initially, If I wished to draw some text to my game’s HUD, I would do something like this:
HUDSprites.DrawString(HUDFont, "score: " + score.ToString(), new Vector2(50,50), Color.Black);
what I didn’t realize was that each time I attempted to render text like this, the string concatenation was causing the creation of a new string, resulting in the creation of garbage. calling ToString on my score integer was also creating a new string, resulting in even more garbage! A bit of research revealed that DrawString also supports passing in a StringBuilder, meaning this instance of garbage creation could be alleviated by tweaking the above code a bit:
StringBuilder sb = new StringBuilder(); ... sb.Clear(); sb.Append("score"); StringBuilderExtensions.AppendNumber(sb,score); HUDSprites.DrawString(HUDFont, sb, new Vector2(50,50), Color.Black);`

here StringBuilderExtensions.AppendNumber is a method I found which appends a number to a string builder one character at a time using a fixed size buffer to avoid dynamic memory allocation. I can’t seem to find the original source now, but this method appears to function roughly equivalently: http://xboxforums.create.msdn.com/forums/p/45512/304609.aspx#304609

use pre-defined scratch variables for temporary values and intermediate calculations
Much like above, the creation of dynamically allocated Vector2s and Rectangles each frame will also lead to a buildup of garbage. For Vector2’s that won’t change (ie. the position of the score indicator on my HUD) simply predefining the score position once during game initialization will do:
Vector2 textPos = new Vector2(50,50); ... HUDSprites.DrawString(HUDFont, sb, textPos, Color.Black);

If a Vector will change each frame, such as one used for sprite rendering, a single Vector can be allocated during game initialization as a scratch variable, and be re-positioned each time we need to use it. In my case, when rendering images with arbitrary rotation, I would specify a rectangle for the image position, as well as a Vector2 for the origin. Rather than creating a new Rectangle and Vector2 for each render, I simply re-used two previously allocated ones, in a manner similar to this:

Rectangle rect;
Vector2 pos;
...
rect.x = center.x;
rect.y = center.y;
rect.width = bounds.width;
rect.height = bounds.height;
pos.x = halfwidth;
pos.y = halfheight;
sprites.Draw(images[obj.sprite], null, rect, null, pos, (float)MathHelper.ToRadians((float)obj.rot), null, Color.White * obj.opacity, SpriteEffects.None, 0);

recycle frequently created and deleted objects
The last tip I wish to share is more game specific. In the project I am currently working on, many bullets are created and destroyed over the course of a single level. Simply creating a new bullet each time one is required and destroying the bullet once it is no longer active quickly leads to a massive waste of dynamic memory. The solution I decided on was to use a pool of re-usable bullet objects, tagged with ids to indicate their behavior type, and designed with reset methods to easily return them to a fresh state when needed for re-use. The code itself is fairly intertwined with the rest of my project code, making picking out a standalone code sample a bit tricky, so instead I will simply link to what appears to be a good read on object pooling in games http://gameprogrammingpatterns.com/object-pool.html

1 Like