CodeWarrior Arena memory management

cluster_fsck

New Tinkerer
Oct 9, 2022
4
2
3
Not sure if anyone's interested, but documenting just in case ;)

I'm working on a few retrocomputing programming projects for classic Mac OS and am reacquainting myself with the joys of the Memory Manager, and, honestly, having to really worry about memory management again. As I'm designing the data model and structures for one of the projects I'm working on, and as I was re-reading the documentation, I was reminded of a few things by the Inside Macintosh authors:

Whenever possible, you should allocate memory in relocatable blocks.

If you're just getting into programming on classic Mac OS, non-relocatable memory is allocated using `NewPtr()` or `NewPtrClear()` and relocatable memory, called Handles, are allocated using `NewHandle()`. Handles are pointers to pointers and allows the OS to move memory around inside the flat memory model. The problem is that, as the above quote states, if you allocate and deallocate a lot of memory using non-relocatable pointers, you'll get what's called "heap fragmentation" and eventually your app won't be able to allocate any additional memory. This problem is somewhat ameliorated on machines with more RAM, but on early Macs this was a problem.

Again, our helpful authors of Inside Macintosh are looking out for us, but don't quite provide a working solution:

Using relocatable blocks makes the Memory Manager more efficient at managing available space, but it does carry some overhead. As you have seen, the Memory Manager must allocate extra memory to hold master pointers for relocatable blocks. It groups these master pointers into nonrelocatable blocks. For large relocatable blocks, this extra space is negligible, but if you allocate many very small relocatable blocks, the cost can be considerable. For this reason, you should avoid allocating a very large number of handles to small blocks; instead, allocate a single large block and use it as an array to hold the data you need.

As I was reading that last sentence, some random synapse fired in my brain, yanking in a memory management scheme I'd long forgotten about along with my own internal pointer to some code that might help. Classic Mac OS isn't the only OS that can be impacted by memory fragmentation, but it's definitely where the problem can be most acutely felt. At some point, I remember coming across arena memory management and it I relearned it to help with the above problem and make memory management for my app a little easier.

Here's a fairly recent blog post about arena memory management with a nice overview of how the concept works with examples centered around standard C memory allocation APIs. The gist is that you use an Arena Allocator to management that large block of memory to control access and use/free pointers from that block instead of calling `malloc()` and `free` (or in the case of classic Mac OS `NewPtr()` and `DisposePtr()`.

That article reminded me about a very talented Mac programmer, Simon Fraser (of MT-Newswatcher fame, among other things), who created a Mac OS 9 code profiling app called Chronoscope. Simon kindly provides the source code for Chronoscope and if you dig through it, he also has a nice implementation of arena memory management embedded within.

Enabling arena memory management in your app isn't terribly difficult, but it's great to have a guide in actual source code (albeit C++, which I don't have a great relationship with due to some horrible early career development in Win32 and ActiveX) that's Mac OS-specific.

If you're writing an app that may require a lot of memory allocation/de-allocation, give the article a read and check out Simon's code. Cheers!