On 17-Aug-09, at 12:14 AM, James Long wrote:
Marc Feeley wrote:
Of course the best situation would be to have a real-time garbage collector, but QuantZ shows that it is not necessary for a real-time game if you are careful how much and when you allocate.
I second this. I've been developing 3d, rather intensive, iPhone games with Gambit Scheme. I've had no problem getting them to run smoothly with a simple call to ##gc every frame. Sometimes it requires a little more work of minimizing allocations, but that usually is part of the profiling process anyway.
I used to really fear the GC, to the point where I didn't even want to invest the time making a game to see how it would be. But it's totally workable.
- James
I should add that there are a number of tricks to reduce the GC pause time. Here are a few:
1) Use "permanent" objects (i.e. literals in the code), or "still" objects, instead of "movable" objects. This eliminates the copying cost that comes with movable objects. This is particularly useful for raw numerical data. For example, use (##still-copy (u8vector 1 2 3)) to make a "still" copy of the movable u8vector.
2) Allocate objects on the C heap, as "foreign" objects, and access the data through the C interface. It is a rather low-level approach, but if done at judicious places with the right abstractions, the code can still be clean. This may even be appropriate when interfacing to some graphics or modeling library which is in C.
3) Structured data that is accessed occasionally (for example, high- scores and preferences), should be serialized to a u8vector, with object->u8vector, and when it needs to be accessed or mutated it can be recreated with u8vector->object. The advantage of this is that the serialized form of the data is handled very quickly by the GC if it is a still object (and vectors beyond a certain size, 4k bytes I think, are always allocated as still objects).
4) Trigger the GC at a quiescent state. For example, force the GC by calling ##gc, at the top of each iteration of the animation loop. That way, there should be no temporary data that is live.
I've measured a pause time of about 1 millisecond per 20000 Scheme objects of live data on a moderately fast computer without using the above tricks. Given that a 60 frames per second rate means 16 milliseconds per frame, you can have 100000 objects and still have 11 milliseconds per frame left for generating the frame. With the above tricks, these 100000 objects can represent a lot of data.
Marc