4 ms·
It depends. Sure you can preload all your world props and level entities, but what about things like projectiles being fired, travelling, and then being de-all
by aethr 12y ago
It depends. Sure you can preload all your world props and level entities, but what about things like projectiles being fired, travelling, and then being de-allocated?
A good strategy for handling this in a GC'd language is using the factory / pool patterns, so during level loading you instantiate 100 "empty" projectile entities that you can re-use. When a projectile is "fired" you request a Projectile from the ProjectilePool, add its initial position/speed/whatever, then add it to the world. It goes through its trajectory, maybe hits a wall, and then you release it back to the ProjectilePool where it is cleared and can be re-used later.
But what if you need 101 projectiles...?
- AYBABTME 12y agoHow big would a projectile be? I'm not super familiar with how games encode their state, but I doubt things like projectiles would account for much memory. Which makes me think that it wouldn't cause problems with GC. Just guessing =P
- aethr 12y agoThat's true, but as slimsag pointed out below, long GC pauses (which are what we're trying to avoid) are caused by large numbers of heap-allocated objects, not by the size of the objects.
- chipsy 12y agoThe 101 projectiles case is not such a useful what-if in practice. It's a game, so your final tuning comes down to "what will hit my framerate target and memory budget," not what a user requested. If it struggles to keep up with 101 projectiles, you have to either design it down or accept dropped frames in the most demanding situations. So a pool's size limit acts as a guide for the other budgeting considerations anyway - and it plays well with the traditionally constrained memory budgets of console games. Of course, AAA game engines today will employ custom low-level allocation strategies in order to squeeze out the last few percentage points where they deal with dynamic data - but if your aims are more modest, and you harken back to 80's era gaming, most of those games had a nearly or entirely static memory map. Besides being a poor fit for those tiny microprocessors, dynamic allocation enables out-of-memory and fragmentation errors to exist, leading us back to the "hard limits on instancing" strategy again. GC still incurs overhead where it has to trace, even if you've pooled everything. Reference counting pulls ahead of tracing collectors in the situation of heavy object persistence, despite being more expensive as a general allocation method. As well, it has predictable latency, which is more important for meeting real-time requirements. (N.B. as systems parallelize, they become more bound by latency considerations. Seven workers may finish early, but delivery will still get bottlenecked by the eighth slow one.)