Question on Portable Memory Management Syntax
Eric Wayne Sink
esink at turia.dit.upm.es
Tue Feb 19 00:34:00 AEST 1991
Here's a question for everyone. It's kind of subjective, so all
opinions welcome. Please respond by posting (unless the question is
inappropriate) as I usually do read this newsgroup. :-)
Given : There is a piece of software which must be portable between
the Macintosh, and some more generic platform. For those of you
unfamiliar with programming on the Mac, the following will explain the
constraint of the problem :
The Mac memory manager performs an order of magnitude better if
most or all dynamically allocated blocks of memory are allocated as
'handles' instead of pointers. A handle is pointer to a master
pointer. The Memory manager reserves the right to move your block
of memory at well defined times. When it does so, the master
pointer is changed. For this reason, most programs which allocat
lots of memory at runtime look like this on the Mac :
struct mystruct **theHandle;
theHandle = NewHandle(sizeof(struct mystruct));
(*theHandle)->someMember = whatever;
instead of the usual :
struct mystruct *thePointer;
thePointer = malloc(sizeof(struct mystruct));
thePointer->someMember = whatever;
The crucial issue here is finding a syntax for referencing struct
members. This syntax must be usable on both platforms.
The piece of software in question allocates a LOT of
memory at run time. In order to handle portability as described
above, I see 3 possible solutions, each with advantages and
disadvantages :
1. Always use malloc. This will result in HORRIBLE performance
on the Macintosh, so I consider this option out of the question.
Please, no flames about the Mac Memory Manager.
2. Always use handles. This is done by implementing a simple
version of the Mac memory manager by using malloc. Each call to
NewHandle allocates the correctly sized block with a malloc call,
and allocates a master pointer, also with malloc, setting
that pointer to point to the block, and returns the address of
the master pointer. (Of course, this memory manager is not going
to go moving blocks around like the Mac does.) Disadvantages here
are that every struct reference potentially involves an extra
redirection on a platform which does not need it. An advantage
is that I would probably not merely allocate a master pointer,
but would allocate a small struct containing the master pointer
as well as the size of the block, so better memory usage
statistics could be kept. An example implementation of a very
simple NewHandle :
void **NewHandle(long size)
{
void **result;
result = malloc(sizeof(void *));
*result = malloc(size);
return result;
}
3. Use the preprocessor to allow usage of the best method for
each platform. In this case, we do something like the following :
#ifdef MAC
#define STRUXMEMBER(s,m) ((*s)->(m))
typedef struct mystruct **BLOCKHP;
#else
#define STRUXMEMBER(s,m) ((s)->(m))
typedef struct mystruct *BLOCKHP;
#endif
Then, every struct reference looks like this :
BLOCKHP GetMemoryBlock(long size);
/* The definition of GetMemoryBlock has #ifdef's to return the
correct type. */
BLOCKHP theRef;
theRef = GetMemoryBlock(sizeof(struct mystruct));
STRUXMEMBER(theRef,someMember) = whatever;
Option 2 introduces inefficiency into the program. Option 3
introduces undesirable syntactic changes to the source. Which is
better ? Is the method of option 3 too ugly ? Are there compromises
worth considering ?
Any and all comments appreciated.
Eric W. Sink | Putting the phrase |All opinions
Departamento de Telematica | "Frequently Asked" |are mine and
Universidad Politecnica de Madrid| in your kill file is |not necessarily
esink at turia.dit.upm.es | not recommended. |yours.
More information about the Comp.lang.c
mailing list