Memman
Volume Number: 7
Issue Number: 9
Column Tag: Programmer's Forum
A Memory Manager for the Rest of US 
By Jordan Zimmerman, Pacific Grove, CA
A Memory Manager for the Rest Of Us: The Evolution of Portable Virtual
[Jordan Zimmerman lives in Burbank, California where he drinks fresh ale,
plays Smash T.V. and writes Movie Magic Scheduling for Screenplay Systems, Inc.]
Our story begins with a humble Macintosh programmer faced with what is
becoming the issue of the 90’s: there are people in the world who insist on having
windows on their blue boxes.
I was confronted with the task of reconciling the different memory management
schemes of the Macintosh and Windows 3.0. In the process of solving this, a memory
management scheme was developed that would be useful regardless of the porting issues.
This memory manager automatically handles virtual memory (without the need for
System 7 or a PMMU), is portable, and traps a multitude of errors and crashes caused
by mistakes in memory usage.
While the full-blown manager is beyond the scope of this article; what follows is
an outline that should be all one needs to write such a manager.
At this point, I must give due credit to my co-workers Ken Smith and Mark
Guidarelli who helped design our Memory Manager, Memman.
In the Beginning
It has been my experience that the Windows 3 API (Application Programming
Interface) is less flexible than the Macintosh’s. A perfect example is the respective
memory managers.
While both platforms use the label “Handle” for their basic type of memory,
they are really very different animals. On the Mac, a Handle points to a real location in
memory. At that location there is another pointer that points to your data. Once the OS
returns an allocated Handle, you are free to use it at will - you don’t need to check with
the OS before using it (except, of course, to lock it).
Under Windows, the Handle it returns is merely a reference. It doesn’t point to
any real memory. In order to get a pointer to real memory, you have to go through an
OS call. When you are done using the real memory, you make another call to let the OS
know you’re through.
The restrictions of the Windows model didn’t give us a lot of choice. Ultimately,
it made a lot more sense to try to fit the Mac model into the Windows model than it did
to try it the other way around.
And Then There Was Light
It quickly became apparent how much control the memory manager would have,
given the constraints on the user of the manager. I could count on several things:
a) I’d know whenever memory was or wasn’t being used;
b) I’d have knowledge of every allocation made; and
c) I could do whatever I wanted with the data of an allocation when it wasn’t being
used so long as I restored its condition before it was needed again.
The Window’s Model
Windows has five basic memory routines. They are:
a) GlobalAlloc() - allocates a block of memory;
b) GlobalReAlloc() - changes the size of an allocation;
c) GlobalLock() - returns a real pointer to memory;
d) GlobalUnLock() - signals that real memory is done being used; and
e) GlobalFree() - disposes of an allocation.
So, it seemed simple enough to fit the Macintosh memory model into Windows’ -
just put wrappers around all memory calls.
Memman is born
This is the basic structure of Memman:
/* 1 */
#ifdef windows
typedef cookie_t HANDLE
#elif macintosh
typedef cookie_t Handle
#endif
cookie_t MMAlloc(long size);
void MMRealloc(cookie_t hdl,
long new_size);
void *MMUse(cookie_t hdl);
void MMUnuse(cookie_t hdl);
void MMFree(cookie_t hdl);
The cookie_t is what we call around the office a “magic cookie” - a reference to
something that is unusable by itself. In Memman, the magic cookie is a Handle on the
Macintosh and a HANDLE on Windows. But that doesn’t really matter to the user of the
manager.
The Memman model ports perfectly between the two platforms:
MEMMAN Macintosh Windows
-------------------------------------------------
MMAlloc NewHandle GlobalAlloc
MMRealloc SetHandleSize GlobalReAlloc
MMUse HLock GlobalLock
MMUnuse HUnlock GlobalUnLock
MMFree DisposHandle GlobalFree
Memman imposes some constraints on a program that Macintosh programmers
won’t be used to.
Before you read to or write from memory, you MUST call MMUse() to get a real
pointer to memory. When you are through reading/writing, you MUST call
MMUnuse(). This is a very different way of coding. The program becomes a “client” of
the Operating System. On the Mac, it’s somewhat the other way around normally.
MMUse() can be unlimitedly nested. However, for every MMUse(), there must
be an MMUnuse() eventually.
Here’s an example:
/* 2 */
/* the Mac way of allocating memory and
then writing to it */
. . .
short **short_array;
short *short_ptr;
short_array = (short **)NewHandle(10 *
sizeof(short);
short_ptr = *short_array;
short_ptr[1] = 1;
short_ptr[2] = 2;
...