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.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Firetask Pro 4.2.2 - Innovative task man...
Firetask Pro uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask Pro's "Today" view shows all... Read more
Bookends 13.4.3 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
LibreOffice 6.4.5.2 - Free, open-source...
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
Thunderbird 68.10.0 - Email client from...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Firefox 78.0.1 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
BetterTouchTool 3.389 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Slack 4.7.0 - Collaborative communicatio...
Slack brings team communication and collaboration into one place so you can get more work done, whether you belong to a large enterprise or a small business. Check off your to-do list and move your... Read more
OsiriX Lite 11.0.3 - 3D medical image pr...
OsiriX Lite is an image processing software dedicated to DICOM images (".dcm" / ".DCM" extension) produced by medical equipment (MRI, CT, PET, PET-CT, ...) and confocal microscopy (LSM and BioRAD-PIC... Read more
Wireshark 3.2.5 - Network protocol analy...
Wireshark is one of the world's foremost network protocol analyzers, and is the standard in many parts of the industry. It is the continuation of a project that started in 1998. Hundreds of... Read more
Dabble 1.6.1 - Organize your manuscript,...
Dabble organizes your manuscript, story notes, and plot. Dabble simplifies the story, leaving more room in your brain to create, which is what being a writer is really about. Organize your story.... Read more

Latest Forum Discussions

See All

Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »
The King of Fighters Allstar's late...
The King of Fighters ALLSTAR, Netmarble's popular action RPG, has once again been updated with a plethora of new content. This includes battle cards, events and 21 new fighters, which increases the already sizeable roster even more. [Read more] | Read more »
Romancing SaGa Re;univerSe, the mobile s...
Square Enix latest mobile spin-off Romancing SaGa Re;univerSe is available now globally for both iOS and Android. It initially launched in Japan back in 2018 where it's proven to be incredibly popular, so now folks in the West can finally see what... | Read more »
Away: Journey to the Unexpected is a sto...
Away: Journey to the Unexpected looks really quite lovely. Stylish, cute, and clearly heavily inspired by Japanese animation, it's amongst the best-looking mobile games on the horizon. Developed by a two-person team, this story-driven rogue-lite... | Read more »

Price Scanner via MacPrices.net

July 4th Sale: Woot offers wide range of Macs...
Amazon-owned Woot is blowing out a wide range of Apple Macs and iPads for July 4th staring at $279 and ranging up to just over $1000. Models vary from older iPads and 11″ MacBook Airs to some newer... Read more
Apple Pro Display XDR with Nano-Texture Glass...
Abt Electronics has Apple’s new 32″ Pro Display XDR model with the nano-texture glass in stock and on sale today for up to $144 off MSRP. Shipping is free: – Pro Display XDR (nano-texture glass): $... Read more
New 2020 Mac mini on sale for up to $100 off...
Amazon has Apple’s new 2020 Mac minis on sale today for $40-$100 off MSRP with prices starting at $759. Shipping is free: – 2020 4-Core Mac mini: $759 $40 off MSRP – 2020 6-Core Mac mini: $998.99 $... Read more
July 4th Sale: $100 off every 2020 13″ MacBoo...
Apple resellers have new 2020 13″ MacBook Airs on sale for $100 off Apple’s MSRP as part of their July 4th sales. Starting at $899, these are the cheapest new 2020 MacBooks for sale anywhere: (1) B... Read more
This hidden deal on Apple’s site can save you...
Are you a local, state, or federal government employee? If so, Apple offers special government pricing on their products, including AirPods, for you as well as immediate family members. Here’s how... Read more
Apple Watch Series 3 models on sale for new l...
Amazon has Apple Watch Series 3 GPS models on sale for $30 off MSRP, starting at only $169. Their prices are the lowest available for these models from any Apple reseller. Choose Amazon as the seller... Read more
Deal Alert! Get these refurbished 2018 13″ Ma...
Apple has restocked and lowered prices on select Certified Refurbished 2018 13″ MacBook Airs, starting at only $679. Each MacBook features a new outer case, comes with a standard Apple one-year... Read more
July 4th Sale: 13″ 2.0GHz MacBook Pros for $2...
B&H Photo has new 2020 13″ 2.0GHz MacBook Pros on sale for $200 off Apple’s MSRP as part of their July 4th sale. Prices start at $1599. These are the same MacBook Pros sold by Apple in their... Read more
July 1 only: $100 off Apple iPhone 11, 11 Pro...
Boost Mobile is offering Apple iPhone 11, 11 Pro, and iPhone 11 Pro Max models for $100 off MSRP with service. Their discount reduces the cost of an iPhone 11/64GB to $599, iPhone 11 Pro to $899 for... Read more
Apple offers $50-$100 Education discount on i...
Purchase a new 12.9″ or 11″ iPad Pro at Apple using your Education discount, and Apple will take $50-$100 off their MSRP. All teachers, students, and staff of any educational institution with a .edu... Read more

Jobs Board

Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
*Apple* Mac Product Engineer - Barclays (Uni...
Apple Mac EngineerWhippany, NJ Support the development and delivery of solutions, products, and capabilities into the Barclays environment working across technical Read more
Blue *Apple* Cafe Student Worker - Pennsylv...
…enhance your work experience. Student positions are available at the Blue Apple Cafe. Employee meal discount during working hours. Duties include food preparation, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.