TweetFollow Us on Twitter

Memman
Volume Number:7
Issue Number:9
Column Tag:Programmer's Forum

Related Info: Memory Manager

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 Memory

[Jordan Zimmerman lives in Burbank, California where he drinks fresh ale, plays Smash T.V. and writes Movie Magic Scheduling for Screenplay Systems, Inc.]

Introduction

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;
...

/* now, the Memman way */
. . .
cookie_treference;
short   *short_ptr;

reference = MMAlloc(10 * sizeof(short));
short_ptr = (short *)MMUse(reference);
short_ptr[1] = 1;
short_ptr[2] = 2;
/* etc. */
MMUnuse(reference);
. . .

Where’s the VM Beef?

So how does this get us Virtual Memory? Given the control that Memman has over memory allocation and usage, Virtual Memory becomes somewhat simple.

What is Virtual Memory, Anyway?

Virtual Memory is a technique that allows an application to access more memory than is physically present in the system. Data is paged to and from disk as needed, thus giving the appearance of more memory than is really available.

Under System 7, this is done on a hardware level by the Paged Memory Management Unit (PMMU). This is the fastest and most desirable way to implement Virtual Memory. But there is nothing stopping the lowly software programmer from doing it manually.

Today’s operating systems provide sophisticated disk I/O and memory managers. These are all a programmer needs to do Virtual Memory.

Memman knows about every allocation that is made. It also knows whenever an allocation is or isn’t being used. So, the first thing to do is to keep track of every allocation made through MMAlloc().

/* 3 */

typedef longhdl_t;

typedef struct {
 cookie_t platform_hdl;
 long   size;
 void   *ptr;
 short  access_cnt;
} alloc_rec;

Memman keeps an array of alloc_recs. Every time MMAlloc() is called, an entry into this array is stored. platform_hdl is a Handle on the Mac or a HANDLE on Windows. Because there is no equivalent to the Mac’s GetHandleSize() on Windows, size stores the size of the allocation.

Instead of MMAlloc() returning a cookie_t, Memman defines its own “magic cookie”, hdl_t. This is an offset into the array of alloc_recs.

ptr is NULL if the allocation isn’t currently being “used” (i.e. MMUse() hasn’t been called) or a real memory location if it is being used. This is done as an optimization. If MMUse() is called in a nested way, there is no need to go through the OS (HLock() or GlobalLock() ) to get a pointer.

access_cnt is the number of unbalanced times MMUse() has been called for the allocation. This is how Memman determines if an allocation is in use or not. When allocated, the access_cnt is set to zero. Every time MMUse() is called, it is incremented by one. Every time MMUnuse() is called it is decremented by one. When the access_cnt is zero, Memman knows that the allocation is not being used.

It is the knowledge of when an allocation is in use or not that allows us to do VM. When an allocation isn’t in use, its data can be stored on disk (however, you’d probably only want to do this when memory is tight). Let’s change alloc_rec a little.

/* 4 */

typedef longhdl_t;

typedef struct {
 cookie_t platform_hdl;
 long   size;
 void   *ptr;
 short  access_cnt;
 long   location;
} alloc_rec;

Memman uses the location field to determine whether or not an allocation is in memory or on disk. MMUse() is responsible for reading in a paged allocation. If location >= 0, then the allocation’s data is on disk; otherwise, location == -1.

A simple implementation of MMAlloc(), MMUse() and MMUnuse() for the Mac might look like this:

/* 5 */

alloc_rec **alloc_array;

hdl_t MMAlloc(long size)
{

 alloc_rec*alloc_ptr;
 Handle h;
 long   old_size;
 hdl_t  hdl;

 /* get some real memory from the OS */
 h = NewHandle(size);
 if ( MemError() )
 DoError();

 /* add another alloc_rec */
 old_size = GetHandleSize(alloc_array);
 SetHandleSize(alloc_array,old_size + 
 sizeof(alloc_rec));
 if ( MemError() )
 DoError();

 /* get the index into the array */
 hdl = old_size / sizeof(alloc_rec);
 alloc_ptr = (*alloc_array)[hdl];

 /* store away the information */
 alloc_ptr->platform_hdl = h;
 alloc_ptr->size = size;
 alloc_ptr->ptr = NULL;
 alloc_ptr->access_cnt = 0;
 alloc_ptr->location = -1;/* in memory */

 return hdl;

} /* MMAlloc */

void *MMUse(hdl_t hdl)
{

 alloc_rec*alloc_ptr;
 void   *ptr;

 /* hdl is an index into the array of alloc_recs */
 HLock(alloc_array);
 alloc_ptr = (*alloc_array)[hdl];

 /* make sure it’s in memory */
 if ( alloc_ptr->location >= 0 )
 load_from_disk(alloc_ptr);

 /* increment the access_cnt and lock the Handle if necessary */
 if ( ++alloc_ptr->access_cnt > 1 )
 ptr = alloc_ptr->ptr;
 else {
 HLock(alloc_ptr->platform_hdl);
 ptr = *alloc_ptr->platform_hdl;
 }

 HUnlock(alloc_array);

 return ptr;

} /* MMUse */

void MMUnuse(hdl_t hdl)
{

 alloc_rec*alloc_ptr;

 alloc_ptr = (*alloc_array)[hdl];

 if ( --alloc_ptr->access_cnt > 0 )
 return;/* handle is still in use, keep it locked */

 alloc_ptr->ptr = NULL;

 HUnlock(alloc_ptr->platform_hdl);

} /* MMUnuse */

Memman opens a temp file that stores any paged data. Memman defines a function, MMPage(), that is used to page data to disk. This would probably be called from the GrowZone or could be setup to be called automatically by MMAlloc() (if NewHandle() failed).

Here’s a simple implementation of MMPage():

/* 6 */

/* page out “needed” bytes of data */
void MMPage(long needed)
{

 alloc_rec*alloc_ptr;
 long   total = 0;
 long   i;
 long   size;

 size = GetHandleSize(alloc_array);
 HLock(alloc_array);

 alloc_ptr = *alloc_array;

 /* go through all allocations paging them out until total >= needed 
*/
 for ( i = 0; i < size; ++i  ) {
 if ( alloc_ptr->location == -1 ) {
 long   offset;

 offset = get_disk_block(alloc_ptr->size);
 write_data(alloc_ptr->platform_hdl,
 alloc_ptr->size,offset);
 alloc_ptr->location = offset;
 DisposHandle(alloc_ptr->platform_hdl);
 
 if ( (total += alloc_ptr->size) >= needed )
 break;
 }
 }

 HUnlock(alloc_array);

} /* MMPage */

You might consider writing MMPage() so that it pages allocations in a “least recently used” fashion. The way Memman does this is by keeping a field (a short) in the alloc_rec that is incremented every time MMUse() is called on the allocation. Allocations with the smallest “time stamp” are the oldest and are paged first. This reduces the likelihood of a lot of swapping to and from disk because an allocation is paged and then read back in, etc.

Ideally, you’ll keep track of any “free” blocks within your temp file and reuse these (a free block is one to which data was paged and then re-read into memory; thus, the block is no longer being used).

Debugging - The Best Benefit

The final benefit of Memman is the automatic debugging it provides. There are several debugging tools that can be built into this memory model.

The first is inherent in the design: Handles are always locked when they are being used. It is a common plague of the Macintosh that a lot of bugs are caused by unlocked handles. With Memman, this is no longer an issue.

The other tools must be added to the memory manager. The following is a list of things we’ve added to Memman at the office. It is by no means an exhaustive list. It seems we are always finding new debugging code to add. You should surround all your debugging code with

/* 7 */

#ifndef NDEBUG
...
#endif

so that it can be turned off easily for the shipping product.

Overdraft Protection

We’ve changed MMAlloc() so that it always allocates 2 bytes more than requested. These two bytes are then set to some unlikely value like 0x1234. Every time MMUse() or MMUnuse() are called, the last two bytes of the allocation are checked and Memman asserts if the value isn’t 0x1234. This catches those pesky bugs where the program writes past the end of an allocation (at a resolution that even Protected Memory can’t achieve!).

Corruption Police

Our Memman has an extra field (a short) in the alloc_rec. This field is used to store a checksum of the data. A checksum of the allocation’s data is stored at MMUnuse() time when the access_cnt gets set to zero (we use a public domain CRC routine). Whenever MMUse() is called, this checksum is verified and Memman asserts if the checksum doesn’t match. This catches memory corruption errors.

The Enforcers

Whenever MMFree() is called, every byte of the allocation’s data is set to 0xff before DisposHandle() is called. This sets up a condition that will always produce incorrect results if an allocation is accessed after it is disposed.

Whenever MMUnuse() is called and the access_cnt gets set to zero, HandToHand() is called on the allocation to duplicate it. The old Handle has every byte set to 0xff and is then disposed. This is the Memman equivalent of Heap Scrambling.

Conclusion

We are using Memman at our office. It has already proved invaluable in weeding out bugs and cleaning up the way we look at memory allocations. Our Memman has been ported to the Mac, Windows and Unix without a hitch.

Even if porting is not an issue for you, the memory model laid out in this article is valuable for any situation. Indeed, the Memman model, I believe, is ideal for every situation and has become an integral part of all the code that I currently write and plan on writing.

 
AAPL
$96.13
Apple Inc.
+0.53
MSFT
$42.86
Microsoft Corpora
-0.30
GOOG
$566.07
Google Inc.
-5.53

MacTech Search:
Community Search:

Software Updates via MacUpdate

Data Rescue 3.2.4 - Recover lost data on...
Data Rescue is a robust and reliable hard-drive recovery solution for your Mac. Recover lost or deleted files, mount corrupted drives, and more -- Data Rescue offers complete relief from crippling... Read more
Adobe Lightroom 5.6 - Import, develop, a...
Adobe Lightroom software helps you bring out the best in your photographs, whether you're perfecting one image, searching for ten, processing hundreds, or organizing thousands. Create incredible... Read more
OneNote 15.2 - Free digital notebook fro...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that’s too important to forget. Whether you’re at... Read more
iStat Menus 4.22 - Monitor your system r...
iStat Menus lets you monitor your system right from the menubar. Included are 8 menu extras that let you monitor every aspect of your system. Some features: CPU -- Monitor cpu usage. 7 display... Read more
Ember 1.8 - Versatile digital scrapbook....
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
OmniPlan 2.3.6 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Command-C 1.1.1 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more

Latest Forum Discussions

See All

Bio Inc. is $0.99 for the Weekend, Recei...
Bio Inc. is $0.99 for the Weekend, Receives Small Update Posted by Ellis Spice on August 1st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Happy 7th Birthday Readdle! Thank You fo...
Happy 7th Birthday Readdle! | Read more »
Sharknado: The Video Game Review
Sharknado: The Video Game Review By Lee Hamlet on August 1st, 2014 Our Rating: :: SHARKNA-DON'TUniversal App - Designed for iPhone and iPad Sharknado: The Video Game brings the craziness of the movies to iOS, though it quickly... | Read more »
Clima (Weather)
Clima 1.0 Device: iOS iPhone Category: Weather Price: $.99, Version: 1.0 (iTunes) Description: Clima show you all weather information, just beautifully simple. A series of color bars can tell you at a glance exactly current... | Read more »
Sticky Soccer Review
Sticky Soccer Review By Andrew Fisher on August 1st, 2014 Our Rating: :: STICK THIS GAMEUniversal App - Designed for iPhone and iPad Sticky Soccer puts too much emphasis on the ‘sticky’ and not enough on the ‘Soccer’ or ‘Fun’.   | Read more »
Graphics-less Apocalyptic Adventure A Da...
Graphics-less Apocalyptic Adventure A Dark Room Goes Free for a Limited Time Posted by Rob Rich on August 1st, 2014 [ permalink ] | Read more »
Fraud Tycoon Review
Fraud Tycoon Review By Rob Thomas on August 1st, 2014 Our Rating: :: UNHEALTHY CREDITUniversal App - Designed for iPhone and iPad Fraud Tycoon is a half-baked, messy, promotional tie-in that does their sponsor no favors whatsoever... | Read more »
Guardians of the Galaxy: The Universal W...
Guardians of the Galaxy: The Universal Weapon is on Sale for the Weekend Posted by Rob Rich on August 1st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Mister Beam Review
Mister Beam Review By Jordan Minor on August 1st, 2014 Our Rating: :: ILLUMINATINGUniversal App - Designed for iPhone and iPad Mister Beam’s puzzles are great. But its platforming? Not so much.   | Read more »
Hook Some More Fun With MapHook’s New Up...
Hook Some More Fun With MapHook’s New Update Posted by Jessica Fisher on August 1st, 2014 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »

Price Scanner via MacPrices.net

13-inch MacBook Airs on sale for $100 off MSR...
B&H Photo has the new 2014 13″ MacBook Airs on sale $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for... Read more
16GB iPad Air on sale for $399, save $100
Best Buy is offering the 16GB WiFi iPad Air for $399.99 on their online store for a limited time. Their price is $100 off MSRP. Choose free shipping or free store pickup (if available). Price is for... Read more
All Over For Tablets Or Just A Maturing, Evol...
CNN’s David Goldman weighs in on tablet sector doom and gloom, asking rhetorically: “Is this the beginning of the end for the tablet?” Answering that, he contends that hysteria and panic are... Read more
Letterspace 1.0.1 – New Free iOS Text Editor...
Bangkok, Thailand based independent developer Sittipon Simasanti has released Letterspace, a new text editor for iPhone, iPad, and iPod touch devices. Letterspace is a note taking app with an... Read more
Save up to $130 on an iPad mini with Apple re...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays available for up to $130 off the cost of new models, starting at $339. Apple’s one-year warranty is included... Read more
iPad Cannibalization Threat “Overblown”
Seeking Alpha’s Kevin Greenhalgh observes that while many commentators think Apple’s forthcoming 5.5-inch panel iPhone 6 will cannibalize iPad sales, in his estimation, these concerns are being... Read more
Primate Labs Releases July 2014 MacBook Pro P...
Primate Labs’ John Poole has posted Geekbench 3 results for most of the new MacBook Pro models that Apple released on Tuesday. Poole observes that overall performance improvements for the new MacBook... Read more
Apple Re-Releases Bugfixed MacBook Air EFI Fi...
Apple has posted a bugfixed version EFI Firmware Update 2.9 a for MacBook Air (Mid 2011) models. The update addresses an issue where systems may take longer to wake from sleep than expected, and... Read more
Save $50 on the 2.5GHz Mac mini, plus free sh...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Save up to $140 on an iPad Air with Apple ref...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more

Jobs Board

Position Opening at *Apple* - Apple (United...
**Job Summary** The Apple Store is a retail environment like no other - uniquely focused on delivering amazing customer experiences. As an Expert, you introduce people Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** At the Apple Store, you connect business professionals and entrepreneurs with the tools they need in order to put Apple solutions to work in their Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.