...without creating garbage? You can try to use StringBuilder but you are limited (how do you format floats, for instance?), and as soon as you call StringBuilder.ToString(), you are back to square one. Also, many of the built-in classes create garbage that
you might not even know about. For instance, using enums as the key in a dictionary creates lots of garbage if you access it every frame. Or assigning delegates or events, or calling anonymous methods, etc etc.
Basically, right now we have to pick through the framework and figure out what is going to create garbage and avoid using it. I would say it is almost impossible to create a complex game that doesn't create garbage during each frame. Ideally we should have
an incremental GC that doesn't trigger long GC cycles so that we don't even need to worry about what creates garbage down to this fine level. If the game creates a small amount of garbage every frame, it should not matter.
I would think this is an overkill / pre-mature optimization. They say the Xbox GC at 1MB allocations, so if you have a small string, say 50 chars, then your periodic GC runs at 1,000,000 bytes / (50 chars * 2 unicode bytes / char) = 10,000 strings / 60 strings
/ sec / 60 sec / min / 60 min / hr = 2.78 hrs.
So, if all your game does is the fps string, then GC will run once every 3 hrs... Of course, that won't be all it does, but you get the idea.
Optimizations you could do is only update the fps once every second, instead of 60 times a sec... Or there's a SpriteBatch.DrawInt32 user routine out there that doesn't use strings... Or do a pre-compute string table...
The idea is to mitigate the effect of GC, not elimitate it. If you can keep GC to a manual process you do that can't be seen by the player, then that's a huge win.