Thursday, November 4, 2010

back to 2d and memory management

I am jumping back into the 2D graphics world by adding a key function.  I had very basic sprite rendering.  I've now added 'rotozoom' support; when drawing a sprite onto the screen, it can be rotated about an arbitrary point and scaled.

Another thing I am dealing with is memory management.  Currently my 'malloc wrapper' is a little unusual:  every single invocation of the allocation function takes a function pointer to use as a destructor.  That way anytime any string, struct, tree or whatever is just 'freed', any other cleanup that needs to happen happens too.

So, what's next?  Reference counting.  I'm adding one new function to the memory allocator:  addref.  It looks like this:

void* alloc( size, function*  destructor):   creates a memory block of 'size' bytes, and binds to the provided destructor.  The returned memory block has a reference count of 1.

void free(void* block);  decrements the reference count of the given block.  If the reference count is decremented to 0, the destructor provided at creation is called.

void* addref(void* block);  adds one to the reference count of the given block.  Returns the given block as the argument.

Additionally, the realloc function should be modified to only succeed when the reference count of the resized block is one;  Think about it: If the reference count is 2, and you're resizing the block, if the block moves how will the other pointer to it be updated?

How do you use this?  To simplify memory management, just follow a few simple rules:

1.  When storing a pointer into another object, use the addref function.  If x is a struct, and y is a pointer to something, instead of:

x->thing=y;

write:

x->thing=addref(y);

2.  Free things when they go out of scope.  Don't be afraid to free things going out of scope in YOUR function even if you think some other struct is hanging on to them; if something else has the reference count will keep the object alive.

Because this reference counting occurs at the 'malloc level' of the application, ANYTHING can now reference counted, even simple strings.  A version of strdup that uses this allocator can do stuff like this:

x = strdup("hello");
y=  addref(x);
z=  addref(x);
free(x);
free(y);
free(z);


Note that reference counting is still not a magic panacea to your memory problems.  There is still the problem of reference cycles.  For my current application, this issue is easy to get around.

No comments: