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
$105.01
Apple Inc.
+0.18
MSFT
$45.45
Microsoft Corpora
+0.43
GOOG
$539.20
Google Inc.
-4.79

MacTech Search:
Community Search:

Software Updates via MacUpdate

BusyCal 2.6.3 - Powerful calendar app wi...
BusyCal is an award-winning desktop calendar that combines personal productivity features for individuals with powerful calendar sharing capabilities for families and workgroups. BusyCal's unique... Read more
calibre 2.7 - Complete e-library managem...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Skitch 2.7.3 - Take screenshots, annotat...
With Skitch, taking, annotating, and sharing screenshots or images is as fun as it is simple.Communicate and collaborate with images using Skitch and its intuitive, engaging drawing and annotating... Read more
Delicious Library 3.3.2 - Import, browse...
Delicious Library allows you to import, browse, and share all your books, movies, music, and video games with Delicious Library. Run your very own library from your home or office using our... Read more
Art Text 2.4.8 - Create high quality hea...
Art Text is an OS X application for creating high quality textual graphics, headings, logos, icons, Web site elements, and buttons. Thanks to multi-layer support, creating complex graphics is no... Read more
Live Interior 3D Pro 2.9.6 - Powerful an...
Live Interior 3D Pro is a powerful yet very intuitive interior designing application. View Video Tutorials It has every feature of Live Interior 3D Standard, plus some exclusive ones: Create multi... Read more
The Hit List 1.1.7 - Advanced reminder a...
The Hit List manages the daily chaos of your modern life. It's easy to learn - it's as easy as making lists. And it's powerful enough to let you plan, then forget, then act when the time is right.... Read more
jAlbum Pro 12.2.4 - Organize your digita...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code!... Read more
jAlbum 12.2.4 - Create custom photo gall...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results Simply drag and drop photos into groups, choose a design... Read more
ExpanDrive 4.1.7 - Access remote files o...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more

Latest Forum Discussions

See All

nPlayer looks to be the ultimate choice...
Developed by Newin Inc, nPlayer may seem like your standard video player – but is aiming to be the best in its field by providing high quality video play performance and support for a huge number of video formats and codecs. User reviews include... | Read more »
Fighting Fantasy: Caverns of the Snow Wi...
Fighting Fantasy: Caverns of the Snow Witch Review By Jennifer Allen on October 24th, 2014 Our Rating: :: CLASSY STORYTELLINGUniversal App - Designed for iPhone and iPad Fighting Fantasy: Caverns of the Snow Witch is a sterling... | Read more »
A Few Days Left (Games)
A Few Days Left 1.01 Device: iOS Universal Category: Games Price: $3.99, Version: 1.01 (iTunes) Description: Screenshots are in compliance to App Store's 4+ age rating! Please see App Preview for real game play! **Important: Make... | Read more »
Toca Boo (Education)
Toca Boo 1.0.2 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0.2 (iTunes) Description: BOO! Did I scare you!? My name is Bonnie and my family loves to spook! Do you want to scare them back? Follow me and I'll... | Read more »
Intuon (Games)
Intuon 1.1 Device: iOS Universal Category: Games Price: $.99, Version: 1.1 (iTunes) Description: Join the battle with your intuition in a new hardcore game Intuon! How well do you trust your intuition? Can you find a needle in a... | Read more »
Ravenous Rampage (Games)
Ravenous Rampage 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: | Read more »
Partia 2 (Games)
Partia 2 1.0.1 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0.1 (iTunes) Description: Partia 2 is a SRPG (Strategy Role-playing) video game inspired by Fire Emblem and Tear Ring Saga series. In a high fantasy... | Read more »
Puzzle to the Center of the Earth Review
Puzzle to the Center of the Earth Review By Campbell Bird on October 23rd, 2014 Our Rating: :: SPELUNKING PUZZLESUniversal App - Designed for iPhone and iPad Do some puzzles to make some platforms in this smart and fun free-to-play... | Read more »
Puzzle to the Center of the Earth – Tips...
Dig this: Would you like to know what we thought of all this puzzling-around the deep recesses of the planet? Check out our Puzzle to the Center of the Earth review! Puzzle to the Center of the Earth is a surprisingly deep and challenging puzzle... | Read more »
Sleep Attack TD Review
Sleep Attack TD Review By Jennifer Allen on October 23rd, 2014 Our Rating: :: A TRUE TWISTUniversal App - Designed for iPhone and iPad Sleep Attack TD is a tower defense game with a difference – you can rotate the layout – and it’s... | Read more »

Price Scanner via MacPrices.net

13-inch 2.5GHz MacBook Pro on sale for $949,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $949.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $150 off MSRP. Price is... Read more
Save up to $125 on Retina MacBook Pros
B&H Photo has the new 2014 13″ and 15″ Retina MacBook Pros on sale for up to $125 off MSRP. Shipping is free, and B&H charges NY sales tax only. They’ll also include free copies of Parallels... Read more
Apple refurbished Time Capsules available sta...
The Apple Store has certified refurbished Time Capsules available for up to $60 off MSRP. Apple’s one-year warranty is included with each Time Capsule, and shipping is free: - 2TB Time Capsule: $255... Read more
Textilus New Word, Notes and PDF Processor fo...
Textilus is new word-crunching, notes, and PDF processor designed exclusively for the iPad. I haven’t had time to thoroughly check it out yet, but it looks great and early reviews are positive.... Read more
WD My Passport Pro Bus-Powered Thunderbolt RA...
WD’s My Passport Pro RAID solution is powered by an integrated Thunderbolt cable for true portability and speeds as high as 233 MB/s. HighlightsOverviewSpecifications Transfer, Back Up And Edit In... Read more
Save with Best Buy’s College Student Deals
Take an additional $50 off all MacBooks and iMacs at Best Buy Online with their College Students Deals Savings, valid through November 1st. Anyone with a valid .EDU email address can take advantage... Read more
iPad Air 2 & iPad mini 3 Best Tablets Yet...
The new iPads turned out to be pretty much everything I’d been hoping for and more than I’d expected.”More” particularly in terms of a drinking-from-a-firehose choice of models and configurations,... Read more
Drafts 4 Reinvents iOS Productivity App
N Richland Hills, Texas based Agile Tortoise has announced the release of Drafts 4 for iPhone and iPad. Drafts is a quick capture note taking app with flexible output actions. Drafts 4 scales from... Read more
AT&T accepting preorders for new iPads fo...
AT&T Wireless is accepting preorders for the new iPad Air 2 and iPad mini 3, cellular models, for $100 off MSRP with a 2-year service agreement: - 16GB iPad Air 2 WiFi + Cellular: $529.99 - 64GB... Read more
Apple offering refurbished Mac Pros for up to...
The Apple Store is offering Apple Certified Refurbished 2013 Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Jobs Board

*Apple* Solutions Consultant - Apple Inc. (U...
…important role that the ASC serves is that of providing an excellent Apple Customer Experience. Responsibilities include: * Promoting Apple products and solutions Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.