Game Stutter and Garbage Collection

Consistent frame rates are an essential part of the player’s experience of your game. Stutters or drops in frame rates have a wide range of causes, but in engines and frameworks such as Unity, FNA, LibGDX and MonoGame, which use higher-level languages like C# and Java, one of the most common culprits is the Garbage Collector.

If you’ve ever written code in C or C++, you’ll be familiar with the headache of memory management and the pain of tracking down memory leaks.

One solution to this is to automatically manage memory by utilizing garbage collection. High-level languages such as Java and C# use garbage collection, but it is also possible in lower-level languages such as C and C++. Garbage collection is implemented and managed by a Garbage Collector (GC). This post will explore how a GC works and the pitfalls that game developers often encounter.

A Quick Introduction

There are many different GC implementations available. Some are generic and portable, such as BoehmGC, while others are language/runtime specific, such as the G1 Garbage Collector for the JVM-based languages and the CLR GC for .NET languages.

While the models and processes vary between implementations, the underlying principles remain the same. When a program starts, the garbage collector will allocate a large block of memory, often called the heap space.

As the program runs, the collector will allocate memory from the heap as objects are created.

As the heap runs out of available memory, the collector will pause the application, check which objects are no longer referenced, and reclaim/free their memory. Memory management is now automatic for the developer.

While this seems like a good solution, it does come with some pitfalls that game developers must be aware of and carefully handle.

Game Stutter

GC pauses are a significant issue for both software and game developers. Depending on the GC model and the amount of memory to clean up, pauses can last anywhere from less than a millisecond to several seconds. To players, long pauses appear as stutter-y/inconsistent frame rates or even temporary game freezes.

Many developers spend much time optimizing and reducing allocations in their game code to reduce garbage collection frequency and duration.

Several decades of research have gone into optimizing garbage collection and reducing pause times. The outcomes of such research can be seen in language-specific GC implementations; for example, Java/JVM comes with several GC implementations, and C#/CLR includes a wide variety of modes and settings.

Taking advantage of multiple CPU cores and splitting the heap into discrete regions or generations are some commonly used techniques used by GCs to reduce pause times further.

Memory Fragmentation

Another issue for developers is memory fragmentation. The lifetime of objects can range from a few nanoseconds to hours to permanent. The result is that your memory may become highly fragmented.

Fragmentation creates a problem when, for example, your game requests 1 megabyte of memory for an array, but there is no free continuous block of 1 megabyte. There may be several megabytes free in total, but because there is no linear block of memory, 1 megabyte in size, the allocation will fail, and your game will crash.

Many GCs will implement a process called “compaction”. During a garbage collection, the GC will move memory references to the start of the heap, ensuring that the heap maintains its free space in one continuous block.

However, not all GCs do this, and developers often implement software design patterns such as object pooling and caching to reduce allocations and prevent memory fragmentation.

Conclusion

Garbage Collectors are a complex topic, and innovations in this area are expected to continue. Keeping memory and allocations in mind as you develop your game is essential. Luckily there are many tools available to help diagnose memory and allocation issues. I’ll explore these in a later article.

Follow me on Twitter, our company page on LinkedIn for more blog posts.

If you’re encountering performance issues in your game, contact Viridian Software today and work with our expert team to get your game back on track.

Previous
Previous

How does game porting work?

Next
Next

Modern C# on Game Consoles