4.4. Heap management using MEMDBG

The memdbg package provided by IBM C and C++ compiler products provides several useful features, including the user-created heap (explained in this section), to deal with managing the process heap. The user-created heap can be used in your application source codes in order to replace the malloc subsystem calls, such as malloc() and calloc(). It could be seen as a wrapper to the interface to the malloc subsystem and shmat services.

If applications are modified to use the user-created heap, then they can use not only the default process heap, but also the shared memory segments for memory allocation requests.

The user-defined memory allocation functions are provided by the libhu.a library and defined in the header file umalloc.h. You can either handle user-created heaps or the default process heap with the following functions:

  • _ucalloc()

  • _umalloc()

  • _uheapmin()

As shown in Example 4-10 on page 200, the following filesets must be installed on the AIX 5L Version 5.2 system in order to use these functions:

  • memdbg.adt

  • memdbg.aix50.adt

  • memdbg.msg.en_US

Example 4-10. /usr/lib/libhm.a and memdgb.* package
# ls -l /usr/lib/libhu.a
lrwxrwxrwx   1 bin      bin              20 Jan 29 19:47 /usr/lib/libhu.a@ ->
/usr/vac/lib/libhu.a*
# lslpp -w /usr/lib/libhu.a
  File                                        Fileset               Type
  ----------------------------------------------------------------------------
  /usr/lib/libhu.a                            memdbg.adt            Symlink
# lslpp -w /usr/vac/lib/libhu.a
  File                                        Fileset               Type
  ----------------------------------------------------------------------------
  /usr/vac/lib/libhu.a                        memdbg.aix50.adt      Symlink
# lslpp -L memdbg.*
  Fileset                      Level  State  Type  Description (Uninstaller)
  ----------------------------------------------------------------------------
  memdbg.adt                 4.4.3.0    C     F    User Heap/Memory Debug Toolkit
  memdbg.aix50.adt           4.4.3.0    C     F    User Heap/Memory Debug Toolkit
                                                   for AIX 5.0
  memdbg.msg.en_US           4.4.3.0    C     F    User Heap/Memory Debug
                                                   Messages--U.S. English

Note

Although these sub-routines are convenient to use, the following points must be understood before using these sub-routines:

  • Application source codes must be modified to call these routines.

  • These subroutines are not considered as a user-created malloc replacement (see 4.2.5, “User-defined malloc replacement” on page 178). Therefore, the user processes still require the default process heap for the memory allocation requests made by functions in shared libraries, even if you have specified to use shared memory segments for the user-created heap.


More further information about these subroutines, please refer to Chapter 4, “Using Memory Heaps”, in VisualAge C++ Professional for AIX Programming Tasks and Library Reference, SC09-4963.

4.4.1. How to handle a user-created heap

To use a user-created heap, there are some basic tasks, as summarized in the following:

1.
Allocate memory chunks to be used for the user-created heap, depending on the type of memory source:

- Call the system malloc() sub-routine to request memory from the process heap.

- Call the shmget() and shmat() sub-routines to request from the shared memory segments.

2.
Call the _ucreate() sub-routine to create a handle to refer to the allocated memory. The created handle will be used to refer to the allocated memory pool in the subsequent _umalloc() subroutine calls.

3.
Use the user-created heap.

- Call the _umalloc() subroutine with the handle instead of the system malloc() subroutine.

- Call the _ucalloc() subroutine with the handle instead of the system calloc() subroutine.

- Call the _ufree() subroutine with the handle instead of the system free() subroutine.

Note

For any memory object allocated by _umalloc() or _ucalloc(), you can find out from what heap it was allocated by calling the _mheap() sub-routine.

4.
Release the user heap memory before the process exit.

  1. Deallocate the all acquired memory within the user-created heap by the _ufree() function

  2. Destroy the user-created heap with the _udestroy() function with the handle.

  3. Deallocate the memory chunks allocated in the first step depending on the type of memory source:

    • Call the system free() sub-routine to free memory from the process heap.

    • Call the shmdt() and shmctl() sub-routines to remove the allocated shared memory segments from the process address space.

Managing the user-created heap size

Once a user-created heap is fully utilized, further allocation requests from that heap will fail, unless you have added more memory chunks using the _uaddmem() sub-routine. So make sure to allocate a block of memory large enough to satisfy all the memory requests in your program.

Changing the default heap source

The use of _umalloc() and _ucalloc() does not conflict with the malloc subsystem subroutines, such as malloc() and calloc(). If malloc() is called within a user program, then the default process heap would be used to satisfy the memory request, even if the program has allocated a user-created heap in the shared memory segments.

However, if the _udefault() sub-routine with a handle parameter that points to the shared memory segments is called within a user program, then subsequent calls to malloc() and calloc() would start use of the user-created heap.

Note

The default heap source can be changed only when _udefault() is called.


The default heap source changes only for the Pthread that has called _udefault() within a process. You can use a different default heap for each thread of your multi-threaded application program.

The _udefault() function call returns the current default heap, so that the value can be saved and be used later to restore the default heap source. The default process heap is specified by the _RUNTIME_HEAP[6] macro.

[6] The _RUNTIME_HEAP macro is defined in the umalloc.h header file.

Gathering statistical data about user-created heaps

The _ustats() sub-routine reports the following statistical data about the specified user-created heap:

  • How much memory the heap holds (excluding memory used for overhead)?

  • How much memory is currently allocated from the heap?

  • What type of memory is in the heap?

  • The size of the largest contiguous piece of memory available from the heap?

4.4.2. A user-defined heap allocated from shared memory segments

An sample program shown in Example 4-12 on page 203 demonstrates how to use a user-defined heap. The program allocate 512 MB memory in shared memory segments, then calls the following sub-routines in turn:

_ucreate()Creates a handle to refer to the user-created heap.
_umalloc()Allocates memory size of 100000 bytes from the user-created heap.
_ustats()Prints the usage of the user-created heap.
_ufree()Un-allocates the previously created memory object using _umalloc() from the user-created heap.
_udestroy()Destroys the user-create heap.

To compile this program, do the following:

$ cc user_heap.c -lhu

When executed, it prints the output shown in Example 4-11. It allocated a memory chunk size of 100016 bytes (16 bytes are used for overhead to maintain the statistics data) out of shared memory segments size of 512 MB.

Example 4-11. Output from _ustats()
$ a.out
----------------------------------------------------------
Heap information from _ustats():
..heapstat._provided            =  536870384
..heapstat._used                =          0
..heapstat._max_free            =  536870384
----------------------------------------------------------
----------------------------------------------------------
Heap information from _ustats():
..heapstat._provided            =  536870384
..heapstat._used                =     100016
..heapstat._max_free            =  536770368
----------------------------------------------------------
----------------------------------------------------------
Heap information from _ustats():
..heapstat._provided            =  536870384
..heapstat._used                =          0
..heapstat._max_free            =  536870384
----------------------------------------------------------

Example 4-12. user_heap.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <umalloc.h>
#include <sys/shm.h>

#define TWOSEGS 0x20000000

void heapstate(Heap_t usrheap)
{
    _HEAPSTATS heapstat;

    _ustats(usrheap, &heapstat);
    printf("----------------------------------------------------------
");
    printf("Heap information from _ustats():
");
    printf("..heapstat._provided		= %10u
", heapstat._provided);
    printf("..heapstat._used		= %10u
", heapstat._used);
    printf("..heapstat._max_free		= %10u
", heapstat._max_free);
    printf("----------------------------------------------------------
");

    return;
}

int main(void)
{
    int     shmid, rc;
    char    buf[BUFSIZ];
    char    *ptr1, *ptr2, *shmptr;
    Heap_t  myheap;

    if ((shmid = shmget(IPC_PRIVATE, TWOSEGS, IPC_CREAT|S_IRUSR|S_IWUSR))
        < 0) {
        sprintf(buf, "shmget() failed at %d in %s with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
        exit(1);
    }
    if ((shmptr = shmat(shmid, (void *)0, 0)) == (void *) -1) {
        sprintf(buf, "shmat() failed at %d in %s with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
        exit(1);
    }
    /* create a user-created heap. */
    if ((myheap = _ucreate(shmptr, TWOSEGS, _BLOCK_CLEAN
        , _HEAP_SHARED|_HEAP_REGULAR, NULL, NULL)) == (void *)NULL) {
        sprintf(buf, "_ucreate() failed at %d in %s with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
        exit(1);
    }
    heapstate(myheap);
    ptr1 = _umalloc(myheap, 100000);       /*allocate from user heap. */
    heapstate(myheap);
    _ufree(ptr1);
    heapstate(myheap);
    /* destroy user heap. */
    if (_udestroy(myheap, _FORCE)) {
        sprintf(buf, "_destroy() failed at %d in %s with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
        exit(1);
    }

    if ((rc == shmdt(shmptr)) == -1) {
        sprintf(buf, "shmdt() at %d in %s failed with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
    }
    if (shmctl(shmid, IPC_RMID, 0) < 0) {
        sprintf(buf, "shmctl() at %d in %s failed with errno = %d"
            , __LINE__, __FILE__, errno);
        perror(buf);
    }

    exit(0);
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset