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