What pitfalls did you encounter when writing games for the PC with a managed Language like C# and how did you solve them?
Answer
I don't know much about Java, so this is from the point of view of a .net developer.
The biggest one by far is garbage. The .NET garbage collector on Windows does a fantastic job, and you can get away without baby sitting it for the most part. On the Xbox/Windows Phone 7 that's a different matter. If you get stalls every few frames, garbage collection might be causing you problems. At the moment it triggers after every 1MB allocation.
Here are some tips for dealing with garbage. You shouldn't have to worry about most of these in reality, but they may come in handy one day.
- Draw the contents of
GC.GetTotalMemory()
to the screen. This gives you an approximation of the amount of allocated bytes your game uses. If it hardly moves, you're doing OK. If it's going up fast, you have issues. - Try to allocate all your heap objects up front. If you don't allocate everything before the game starts, every time you hit a meg of allocations, your going to stall. No allocations, no collections. As simple as that.
- After loading, call
GC.Collect()
. If you know most of your big allocations are out the way, it's only nice to let the system know. - DO NOT CALL
GC.Collect()
every frame. It might seem like a good idea, keeping on top of your garbage and all that, but remember the only with worse than a garbage collection is over garbage collection. - Look for where your garbage is coming from. There are some common causes like concatenating strings instead of using
StringBuilder
(beware,StringBuilder
isn't a magic bullet, and can still cause allocations!. This means simple operations like adding a number to the end of a string can create surprising amounts of garbage) or usingforeach
loops over collections that use theIEnumerable
interface can also create garbage without you knowing (for example,foreach (EffectPass pass in effect.CurrentTechnique.Passes)
is a common one) - Use tools like the CLR memory profiler to figure out where memory is being allocated. There are loads of tutorials out there on how to use this tool.
- When you know where your allocating during gameplay, see if you can use tricks like pooling objects to lower that allocation count.
- If all else fails, make your collections run faster! The GC on the compact framework follows every reference in your code to figure out what objects are not in use anymore. Refactor your code use less references!
- Remember to use
IDisposable
on classes that contain unmanaged resources. You can use these to clean up memory the GC cannot free up itself.
The other thing to think about is floating point performance. While the .NET JITer does a fair amount of processor-specific optimizations, it cannot use SSE or any other SIMD instruction sets to speed up your floating point maths. This can cause quite a big speed difference between C++ and C# for games. If your using mono, they have some special SIMD maths libraries you can take advantage of.
No comments:
Post a Comment