A long day yesterday - left the house at 6:30am and got home at 8:30pm - 14 hours. But, hey, when your wife phones and says she won't be home till late, it's a perfect opportunity to get in a few more hours.
I was on a roll anyway. I integrated the new bitmapped memory manager (allocator and garbage collector) and it worked! I've had this finished for a while but I've been too chicken to drop it in. It underlies everything and bugs at this level can be both catastrophic and elusive. Just what you don't need. But it seems solid. Perhaps the XP (extreme programming) techniques (simple incremental development and automated tests) really work. And the performance seems at least as good as the old stuff, and probably better. It should be much more efficient space- wise. Minimum allocation is 8 bytes instead of 16. (And there are a surprising number of these tiny objects - e.g. after startup, about 2000 out of 7000 objects are 8 bytes or less!) And there is *no* overhead on the blocks themselves (i.e. no "header" or "trailer"). The only space overhead is the bitmaps. Each bit in the bitmaps controls 8 bytes of heap space, so each bitmap is 1/64 or roughly 1.5% overhead. There are three bitmaps (one to mark block boundaries, one to use for mark/sweep, and one to designate non-pointer blocks) so the overhead is about 4.5%. Most memory managers have an overhead of 4 or 8 bytes per block. On small blocks (the majority in a system like Suneido) this can amount to as much as 25% space overhead. The old memory manager also used a much smaller set of block sizes, so there was more wastage from having to use larger blocks than strictly necessary. And it also kept separate memory pages for each size, so there was also wastage per size. The new allocator is not page based, it simply allocates consecutive memory locations (very fast) and by its nature, the bitmapped garbage collection automatically coalesces all the free space, greatly reducing fragmentation. All in all it seems like a great approach. (You might think that these days, with memory plentiful, space efficiency is not important. But because of caching and virtual memory, it can have a direct effect on speed.)
The new memory manager also supports "non-pointer" allocations. i.e. when you alloc something like a string, that you know will never contain pointers to other heap memory, you can tell this to the memory manager and then it doesn't need to scan these blocks during garbage collection. I made a few changes in the code so strings, numbers, dates, and compiled code are non-pointer. This resulted in about half of the heap being non-pointer, thereby cutting the garbage collection scanning in half.
"finalization" is also supported. You can register a pointer with the memory manager and when the memory it points to is garbage collected (i.e. no more references to it) instead of being free'd it is added to a queue. Then I added an abstract SuFinalize base class (derived from SuValue) that registers instances when they are created. It has a virtual "finalize" method that derived concrete classes define to release their resources. Then in Suneido's main message loop, if there are no messages waiting it removes values from the queue and calls finalize on them. I modified SuFile to derive from SuFinalize, and renamed it's close method to finalize. Voila, files are now automatically closed if you forget to do it. Of course, there's no guarantee on the timing of finalization. Reference counting can detect unreferenced objects immediately and predictably. But conservative garbage collection is not quite so predictable. Often, spurious pointers to objects will keep them "alive" for some time after they are actually "dead". But at least you have some assurance that resources will not "leak" indefinitely. Now I have to modify Suneido's other "resource holding" values to use this facility - e.g. Transaction, Cursor, Image. Windows "handles" will take a little more work because currently they're just treated as integers. I'll have to define a Handle type and change the dll definitions. But this will be an improvement anyway as it will provide some type safety (i.e. stop you from passing any old number as a handle).
Had a great bike ride to work this morning - it was cold, windy, cloudy, and snowing - brisk, you might say. To understand why I would call that "great", you need to know that I leave in three weeks to lead a mountain climbing expedition to an 8000m mountain in Tibet called Shishapangma. So besides the physical training, I'm working on mentally training myself to enjoy "interesting" conditions :-) I've been so wrapped up in Suneido that I'm feeling a little "separation anxiety". But I need the break and I'm looking forward to a simpler, more physical challenge, with a well defined goal and a clear definition of "success".
Anyway, time to get to work - lots to do!