[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

#### 3.9.3.2 Memory leaks

Incorrect memory management may undermine confidence in a library when one wonders what else it gets wrong, but if the worst it does is leave a few bytes unreclaimed, then help is at hand.

The first priority is to assess the seriousness of the situation. Similarly to the way library functions are bracketed with calls to those listed in Inept excess verbiage, the following functions are meant to be placed before and after a call to a library function either for diagnostic purposes or production use.

Function: void avm_manage_memory ()

  After this function is called, all subsequent calls to the standard C functions `malloc`, `free`, and `realloc` are intercepted and logged until the next time `avm_dont_manage_memory` is called. Furthermore, a complete record is maintained of the addresses and sizes of all allocated areas of memory during this time in a persistent data structure managed internally.

Function: void avm_dont_manage_memory ()

  Calling this function suspends the storage monitoring activities initiated by calling `avm_manage_memory`, but the record of allocated memory areas is not erased.

Function: void avm_debug_memory ()

  After this function is called and `avm_manage_memory` is also called, the standard output stream will display a running account of the sizes and addresses of all memory allocations or deallocations as they occur until the next call to either `avm_dont_debug_memory` or `avm_dont_manage_memory`.

Function: void avm_dont_debug_memory ()

  This function stops the output being sent to `stdout` caused by `avm_debug_memory`, if any, but has no effect on the logging of memory management events preformed due to `avm_manage_memory`.

While the latter two are not useful in production code, they can help to clarify an inadequately documented API during development by experimentally identifying the functions that cause memory to be allocated. They can also provide the answer to questions like whether separate copies are made from arrays passed to functions (useful for knowing when it’s appropriate to free them).

Although the console output reveals everything there is to know about memory management during the selected window, the question of unreclaimed storage is more directly settled by the following functions.

Function: void avm_initialize_mwrap ()

  This function has to be called before any other functions from ‘`mwrap.h`’ in order to clean the slate and prepare the static data structures for use. This function might not have to be called explicitly if the client module is part of `avram`, whose main program would have already called it. There is no harm in calling it repeatedly.

Function: void avm_count_mwrap ()

  This function should be called after the last call to any other functions in ‘`mwrap.h`’, when it is expected that all storage that was allocated while `avm_manage_memory` was in effect should have been reclaimed.

  If there is no unreclaimed storage allocated during an interval when memory was being managed, this function returns uneventfully. However, if any storage remains unreclaimed, a message stating the number of bytes is written to `stderr`.

  If `avm_debug_memory` is also in effect when this function detects unreclaimed storage, an itemized list of the unreclaimed memory addresses and their sizes is written to standard output.

Of course, in order for `avm_count_mwrap` to report meaningful results, any memory that is allocated during the interval between calls to `avm_manage_memory` and `avm_dont_manage_memory` must have been given an opportunity to be reclaimed also while this logging mechanism is in effect. However, there may be arbitrarily many intervening intervals during which it is suspended.

On the other hand, any storage that is allocated when memory is not being managed must not be freed at a time when it is (except for freeing a `NULL` pointer, which is tolerated but not encouraged). Doing so raises an internal error, causing termination with extreme prejudice. This behavior is a precaution against library functions freeing storage that they didn’t allocate, which would mean no memory is safe and it’s better for `avram` not to continue.

If these investigations uncover no evidence of a memory leak, then perhaps the relevant library functions are reliable enough to run without supervisory memory management. Alternatively, when memory leaks are indicated, the next function provides a simple remedy.

Function: void avm_free_managed_memory ()

  This function causes all storage to be reclaimed that was allocated at any time while logging of memory allocation was in effect (i.e., whenever `avm_manage_memory` had been called more recently than `avm_dont_manage_memory`). When the storage is freed, no further record of it is maintained.

  A side effect of this function is to call `avm_dont_manage_memory` and therefore leave memory management turned off.

This last function when used in conjunction with the others is therefore the workaround for library functions that don’t clean up after themselves. It may be important to do it for them if repeated calls to the library function are expected, which would otherwise cause unreclaimed storage to accumulate until it curtailed other operations.

One small issue with this function is the assumption that unreclaimed storage is really a leak and not internal library data that is designed to persist between calls. If this assumption is not valid, breakage will occur. However, libraries deliberately making use of persistent data are likely to have initialization and destructor functions as part of their API’s, so this assumption is often justified if they don’t.

An example of using these functions is given below.

In this example, `allocated_library_object` is a hypothetical function exported by an external library that causes storage to be allocated, and `library_reclamation_routine` is provided by the same library ostensibly to reclaim the storage thus allocated. However, the latter is suspected of memory leaks.

The variable `my_data` is declared and used by an `avram` developer who is presumably competent to reclaim it correctly, rather than it being part of an external library. Memory management is therefore enabled during the calls to the library routines but not at other times.

The call to `avm_count_mwrap` is redundant immediately after a call to `avm_free_managed_memory`, because with all managed memory having been freed, no memory leak will ever be detected, but it is included for illustrative purposes.

    #include <avm/mwrap.h>
    ...

    {
      void *behemoth;
      char *my_data;

      avm_initialize_mwrap ();
      avm_manage_memory ();
      behemoth = allocated_library_object (foo, bar);
      avm_dont_manage_memory ();
      my_data = (char *) malloc (100);
      ...
      free (my_data);
      avm_manage_memory ();
      library_reclamation_routine (&behemoth);
      avm_free_managed_memory ();
      avm_count_mwrap ();
      return;
    }

It might be a cleaner solution in some sense to omit the call to `library_reclamation_routine` entirely, because the storage allocated during the call to `allocated_library_object` will be reclaimed perfectly well by `avm_free_managed_memory` without it. Doing so may also be the only option if the library reclamation routine is either extremely unreliable or non-existent. However, the style above is to be preferred for portability if possible. The memory management functions rely on the availability of the system header file `malloc.h`, and GNU C library features whose portability is not assured. If the required features are not detected on the host system at configuration time, conditional directives in the `avram` source will make the `avm_`* memory management functions perform no operations, and the responsibility for memory management will devolve to the possibly less robust external library implementation.

[ < ] | [ > ] |  | [ << ] | [ Up ] | [ >> ] |  |  |  |  | [Top] | [Contents] | [Index] | [ ? ]

This document was generated on November 8, 2012 using texi2html 1.82.