.so page1.s
.Fc "Memory allocation Routines" 1.2 "3/8/89"
.H 1 Introduction
This document describes a set of memory allocation routines which
sit on top of the usual \fImalloc()\fR, \fIfree()\fR and \fIrealloc()\fR
routines which provide aid in diagnosing memory leakage type
bugs, and also aid in designing programs which exhibit good
virtual memory characteristics, ie they do not necessarily
stomp all over the address space causing page faults, etc.
.H 2 Overview
.H 3 "The Memory Checking Routines"
.sp
There are two sets of routines within the memory allocation package -
those to aid in debugging - \fIchk_alloc()\fR, \fIchk_free()\fR, and
\fIchk_realloc()\fR and those to aid in virtual memory thrashing -
\fRvm_alloc()\fR and \fRvm_free()\fI.
.P
The \fIchk_\fR functions work by allocating a piece of memory
just before the block of memory allocated to the user. Special
magic markers are placed in this block. This block is checked
on entry to the \fIchk_realloc()\fR and \fIchk_free()\fR functions
to ensure only a currently valid pointer is being freed or reallocated.
Because of this extra magic block, only memory which has been 
previously allocated via \fIchk_alloc()\fR can be passed to 
\fIchk_realloc()\fR and \fIchk_free()\fR. A memory block which
has been allocated via \fIchk_alloc()\fR must never be passed
to the standard
.I realloc()
or
.I free()
system routines and vice versa.
.P
The 
.I chk_free()
function can detect two sorts of errors - trying to free
a piece of memory which has not been previously allocated (ie a duff
pointer), and trying to free a block of memory which has already been
freed.
.P
These types of errors are common during program development and
the checking routines enhance productivity.
.P
The checking routines should always be used wherever possible - they
add neglible overhead to the performance of existing programs.
Continuous use in a wide variety of programs has shown that they
added practically no overhead to running programs. This is basically
due to the fact that most implementations of the malloc package
are incredibly slow.
.P
In addition the memory checking routines provide a mechanism
for tracking down \fImemory leakage\fR problems - ie bugs
which cause memory to be lost and thus program executable
images to get bigger.
.H 3 "The Virtual Memory Functions"
.sp
The virtual memory functions are designed to provide a simple
mechanism for tuning applications which make heavy use of dynamically
allocated memory and which if run untuned can cause an inordinate amount
of virtual memory paging to occur because of the sparsity of the address
space. Typically this occurs in programs which allocate lots
of little objects together with a few large objects, eg 
creating linked lists of objects. Typically in a linked list,
the list headers are tiny and of unvarying size (maybe 10-20 bytes)
whereas the objects within the list may be large, eg > 1K. In these
cases, a typical linked list package might allocate a linked list
header together with the data object, but since the objects within
the list are not needed as much as the headers the data associated
with each element of the list gets paged into memory even
when only the 10-20 byte header is needed, eg when scanning a list for
an object.
.P
The virtual memory functions help by allocating a large collection
of little memory objects in one memory page. The default allocation
is as many objects as will fit into 8,192 bytes of memory. This
size is chosen since it represents the size of two MMU pages on
a 386 processor and the page size of Sun 3 workstations.
.P
The main caveat to using the virtual memory allocation routines
is that objects allocated via 
.I vm_alloc()
are \fInever\fR freed - they are maintained on a free list on
the assumption that more of the same kinds of objects will be needed
again in the near future. Also, as a consequence of the implementation
objects allocated via 
.I vm_alloc()
may not be changed in size via
.I chk_realloc().
.H 3 "Keeping track of memory allocation."
.sp
The memory allocation routines keep track of how
many items have been chk_alloc()'ed via a counter. This
variable is available as an extern:
.DS I
.ft CW
extern int cnt_alloc;
.DE
.P
A good programming practise during debugging is to keep track of
this variable and if it consistently gets larger, then this
may be indicate of a memory lossage problem.
.H 1 "Compiling and Linking"
The code to implement these routines reside in a file called
\f(CWchk_alloc.c\fR. This file should either be directly linked
in or placed in a library.
.P
The code can be compiled to provide memory allocation tracing.
Normally when memory is allocated via 
.I chk_alloc()
a 4-byte header is prefixed to the block of memory
returned to the calling function. This 4-bye header
contains a magic number used by the other functions to
check consistency.
.P
If the variable \f(CWWHERE\fR is defined at the top of the file,
then an 84-byte header is used instead. In this case, the first
four bytes are the magic number and the other 80 bytes
are used to store the line number and file from which the 
.I chk_alloc()
function was called.
.P
Programs using the memory allocation routines should
include the following header file:
.DS I
.ft CW
# include	"chk_alloc.h"
.DE
This file contains various #define's which when used with
the \f(CWHERE\fR facility described above, cause all
calls to the memory allocation routines to be passed
the \f(CW__FILE__\fR and \f(CW__LINE__\fR pre-processor variables.
.P
The following is the contents of the header file:
.DS I
.ft CW
\s-2
extern char *check_alloc(), *chk_alloc();
extern char *check_realloc(), *chk_realloc();
extern void chk_free();

/* Uncomment next line if you want more detailed location information. */
/*# define	WHERE*/

# define	chk_alloc(size)		check_alloc(size, __FILE__, __LINE__)
# define	chk_realloc(ptr, size)  check_realloc(ptr, size)

\s+2
.DE
.bp
.Fo Name
chk_alloc, chk_realloc, chk_free - memory allocation debugging routines.
.Fo Synopsis
.DS
.ft CW
# include	"chk_alloc.h"

void *chk_alloc(unsigned int size);
void *chk_realloc(void *ptr, unsigned int size);
void chk_free(void *ptr);
.DE
.Fo Description
These routines act as front ends to the standard
.I malloc(),
.I realloc(),
and
.I free()
routines.
.P
These routines check that the pointers passed to the
.I chk_realloc()
and
.I chk_free()
routines are valid pointers to currently allocated memory
(via
.I chk_alloc())
and if not, exit with a suitable error message, and force a core
dump so that a debugger, etc may be used to track down the
cause of the problem.
.P
When the allocation routines have been compiled with the \f(CWWHERE\fR
option, the \fIstrings(1)\fR program can be used on the core
file to track down memory leakages.
Strings produced by the where option look like this:
.DS I
.ft CW
FILE: foo.c LINE: 192
.DE
.P
If a program is suspected of losing memory, then it should
be left running until the process image grows, and then a core
dump should be forced. Then using the strings program it is possible
to see where the different blocks of \fIlost\fR memory have come from.
.Fo Bugs
It is not possible to pass pointers obtained from the standard
.I malloc()
family of routines to the chk_ routines above, or vice versa,
because of the block which is allocated preceeding the users data.
.bp
.Fo Name
vm_alloc, vm_free - virtual memory friendly allocation routines.
.Fo Synopsis
.DS I
.ft CW
char *vm_alloc(unsigned int size, void **freelist);
void vm_free(void *ptr, void **freelist);
.DE
.Fo Description
The 
.I vm_alloc()
function is similar to 
.I chk_alloc()
(it calls it internally), but whenever a piece of memory is requested,
instead of calling 
.I malloc() 
to satisfy the request directly, instead the freelist pointer
.I freelist
is checked to see if there is already a piece of memory
of the desired size is available. If so, then the first
element on the free list is unhooked and returned to the user.
.P
The
.I freelist
variable should be declared as a 
.I void
pointer and initially assigned NULL. 
.I freelist
is used by the virtual memory routines to keep track of free
blocks of memory of the desired size. The variable should
never be modified by the user directly.
.P
When freeing a block of memory allocated by
.I vm_alloc()
the same freelist pointer should be passed to 
.I vm_free().
The memory is not actually freed, but instead is attached to
the head of the freelist pointed to by
.I freelist.
.P
The user should use different freelists if variables of the same
size are used in different manners within the program. Eg all
linked list headers would typically allocated to their own list.
.Fo Example
The following piece of code illustrates how to use these functions:
.DS I
.ft CW
\s-2
void *freelist_ptr = NULL;
struct *fred pf = vm_alloc(sizeof (struct fred), &freelist_ptr);
  .
  .
vm_free(pf, &freelist_ptr);
\s+2
.DE
.Fo Bugs
It is not possible to increase the size of a piece of memory
allocated via 
.I vm_alloc().
.P
The virtual memory functions do not check for the
.I freelist
pointer being corrupted.
.P
No tracing is available for these functions as it is for
the chk_ functions.

