On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
It's interesting to hear do you use D's GC? Or do you use your own custom memory management structure?
How performant is GC?
The reason I'm asking is I'm planning to dive into 3D game dev with D as a hobby in an attempt to create a game I dreamed of since I was a kid. I'd like to know if GC is worth using at all, or should I go with 100% manual memory management.
Any opinion is appreciated. Thanks in advance.
In short, treat GC allocated memory the same way you would treat memory allocated and deallocated with malloc and free. For example, in C++ would someone who knows what they're doing allocate memory for large numbers of individual entities, like particles, in inner loops? No. They would preallocate. Do the same in D.
The GC isn't going to run a collection behind your back. It's only going to run if you do something that triggers an allocation.
@nogc on the functions that are called in your inner loops will make sure you don't trigger a collection at the wrong moment. You have other tools if you need them (emphasis on if you need them), like pausing the GC, or invoking collection runs manually at specific points. This is the sort of thing you dig into if you find the GC is problematic.
I'm going to go out on a limb and say the odds are low that the GC will be a problem for you, and lower still if you are smart about using it. There is a class of games and other applications for which GC is certainly going to be problematic no matter how smart the developer is about using it, but I doubt anyone working on a hobby 3D is going to be anywhere near there. Even going full-on GC and being dumb about using it is going to be just fine for many kinds of games. It's all about the scope of the project and your allocations patterns. I mean, you can be less smart about it for games like Pac-Man, Galaga, etc, but you'll need to think about it more for something like Skyrim. Plan your allocation patterns in a way that makes sense for the game you are making.
To do that, just follow some simple rules. If it doesn't need to be a class, make it a struct. If it can be allocated on the stack, then don't use
new. If there's something that needs heap allocation but you can see a way to easily manage it deterministically, then allocate with malloc instead of the GC. Don't do any allocations, including malloc, in your inner loop. Preallocate arrays for things like particles, or use free lists when you need large numbers of GC-managed objects (not good advice for Java anymore, but almost certainly useful in D). And so on.
In short, the less pressure you put on the GC, the less impactful its collections. The less often you allocate from the GC, the fewer collections it will run. So use it for the things you need it for, but be strategic about when you call the allocations.
This may help you get started: