Memory Management in C CRIS/SIS Data Retrieval Routines

Last Modified Monday, 24-Nov-1997 15:03:49 PST.

All of the C routines in the CRIS/SIS Data Retrieval Libraries use dynamic memory allocation to create a space to place the data structs requested by the user. A pointer to this data filled memory space is then returned to the user. Problems can arise if too many calls to routines which keep allocating more memory are made without deallocating the memory for data which the user no longer cares about.

Because many users would rather not bother about memory management problems, a simple option has been built into most of the get routines: the autoMemoryFreeFlag. autoMemoryFreeFlag is a boolean, either zero (false) or non-zero (true (usually set to 1 for true)). If the user passes autoMemoryFreeFlag = 1 (true), then the pointer to the data which is returned to the user from this call will be stored in the routine itself as well. At the next call the user makes to the same routine, the memory allocated in the prior call will then be deallocated before a pointer to the new data is returned.

For example, if I make the calls

autoMemoryFreeFlag = 1;		/* auto memory free is on */

    /*
    this call finds all the high priority rates between startTime
    and stopTime, allocates memory to store the data, and returns
    a pointer to the newly allocated, data filled memory.  since
    autoMemoryFreeFlag is set, the routine also stores the value
    of this pointer internally, awaiting the next call to
    getGroupHiRates_c.
    */
pHiRates = getGroupHiRates_c(startTime, stopTime, autoMemoryFreeFlag);

    /* do something with the retrieved data... */
while (pHiRates->Second1996 != 0) {
    printf("Second1996 = %ld\n", pHiRates->Second1996);
    pHiRates++;
}

    /* move to the next interval i want to retrieve */
startTime = stopTime;
stopTime = stopTime + 4000;

    /*
    subsequent call to getGroupHiRates_c: first the routine checks
    if it has stored away a pointer to some previously allocated
    memory.  if so, that memory is freed, and the previous value
    of the pointer has now been made invalid!  I.e., if you try
    looking at where that old pointer value points, you'll likely bomb
    your program (if you're lucky.)  the old memory has been released
    for reuse.  The routine now proceeds to do it's normal data
    retrieval, and if autoMemoryFreeFlag is set, it again will keep
    track of the new memeory allocation to deallocate it at the next
    call to getGroupHiRates_c.
    */
pHiRates = getGroupHiRates_c(startTime, stopTime, autoMemoryFreeFlag);

    /* do something with the retrieved data... */
while (pHiRates->Second1996 != 0) {
    printf("Second1996 = %ld\n", pHiRates->Second1996);
    pHiRates++;
}

    /* move to the next interval i want to retrieve */
startTime = stopTime;
stopTime = stopTime + 4000;
 
    /*
    now, for some reason, i wish to hold onto the data i'm retrieving,
    even through subsequent calls to getGroupHiRates_c...
    */
autoMemoryFreeFlag = 0;		/* turn off auto memory free */

    /*
    this call to getGroupHiRates_c first looks to see if it has stored
    a pointer value away to deallocate the associated memory.  since
    the previous call had autoMemoryFreeFlag = 1, the pointer was stored
    and is slated for memory deallocation.  the important thing to understand
    here is that it is the value of autoMemoryFreeFlag at the time of the
    memory allocation that matters.  if auto memory free is on when the
    call is made, that memory will be freed at the next call, even
    if the auto memory free is turned off for that subsequent call.  it
    is a simple formula actually- if the routine finds a stored pointer,
    it deallocates the memory associated with it no matter what the value
    of autoMemoryFreeFlag at the call.  Then, dependent on the current
    value of autoMemoryFreeFlag, the new pointer is either saved
    internally or it is not.  If it is not stored (autoMemoryFreeFlag = 0),
    it will never be deallocated until the user does it him or herself.
    */
pHiRates = getGroupHiRates_c(startTime, stopTime, autoMemoryFreeFlag);
pSaved = pHiRates;	/* now i must track this pointer myself */

    /* do something with the retrieved data... */
while (pHiRates->Second1996 != 0) {
    printf("Second1996 = %ld\n", pHiRates->Second1996);
    pHiRates++;
}

    /* move to the next interval i want to retrieve */
startTime = stopTime;
stopTime = stopTime + 4000;

autoMemoryFreeFlag = 1;		/* decided to turn auto memory free back on */

    /* just another call to getGroupHiRates_c... */
pHiRates = getGroupHiRates_c(startTime, stopTime, autoMemoryFreeFlag);

    /* no need to save this pointer, the memory associated with it will */
    /* be deallocated on the next call to getGroupHiRates_c */

    /* do something with the retrieved data... */
while (pHiRates->Second1996 != 0) {
    printf("Second1996 = %ld\n", pHiRates->Second1996);
    pHiRates++;
}

    /* now, can still access the data stored at pSaved... */
pHiRates = pSaved;

    /* do something with that old data... */
while (pHiRates->Second1996 != 0) {
    printf("Second1996 = %ld\n", pHiRates->Second1996);
    pHiRates++;
}

    /*
    finally, since the memory stored at pSaved will never be automatically
    deallocated (until the program ends, at least), i need to deallocate
    it myself...  (see the man page on free if you are not familiar with it.)
    */
free(pSaved);

	.
	.
	.