zondag 29 maart 2009

Identifying memory leaks in AIX

Dynamic memory allocation happens at run time rather than at the creation of the process. While giving more flexibility to the programmer, it also requires a lot more housekeeping. In large programs, memory leaks are a very common issue, with very unpleasant side effects. Side effects of poor dynamic memory allocation management can include:
- malloc returns with errno set to ENOMEM
- process working segment is growing over time (detected with either ps gv or svmon)
- core dump of the process which has malloc in the stack trace

While an growing process working segment is an indication of a memory leak, it doesn't necessarily mean there is one. It might be perfectly normal for a process to allocate additional memory during its lifetime. However, at some point in time, dynamic memory has to be freed by the application. The following graphs show both a normal and abnormal memory evolution of a process (X-axis -> time , Y-axis -> allocated memory)

Since dynamic memory gets allocated on the process heap, it is automatically cleaned up when the process terminates. This also means that a memory leak isn't that harmful for a process with a short lifetime. However for daemons it is potentially more harmful!

How can memory leaks be tracked down? There are some commercial products available that examine of the memory allocation of processes (f.e. IBM Rational PurifyPlus) but AIX provides a subsystem capable of determining this out of the box. Let's consider the following C code which has a few memory leaks.

#include <stdio.h>
void routineA(){
   char *test=malloc(4);
   fprintf(stdout,"routineA\n");
   fprintf(stdout,"pointer residing at address %p\n",&test);
   fprintf(stdout,"value of pointer %p\n",test);
}
void routineB(){
   char *test=malloc(4);
   fprintf(stdout,"routineB\n");
   fprintf(stdout,"pointer residing at address %p\n",&test);
   fprintf(stdout,"value of pointer %p\n",test);
   free(test);
}
void routineC(){
   char *test=malloc(8);
   fprintf(stdout,"routineC\n");
   fprintf(stdout,"pointer residing at address %p\n",&test);
   fprintf(stdout,"value of pointer %p\n",test);
}
int main(){
   char *test=malloc(4);
   fprintf(stdout,"main\n");
   fprintf(stdout,"pointer residing at address %p\n",&test);
   fprintf(stdout,"value of pointer %p\n",test);
   routineA();
   routineB();
   routineC();
}


Here we can clearly see that the memory allocations in main,routineA and routineC don't get freed. Using the malloc debug subsystem, we are also made aware of this. Moreover, even if we don't have the source, the malloc debug subsystem will give the stack trace.

#export MALLOCTYPE=debug
#export MALLOCDEBUG=report_allocations
#./memleak
main
pointer residing at address 2ff22b10
value of pointer 2000eff8
routineA
pointer residing at address 2ff22ac0
value of pointer 20010ff8
routineB
pointer residing at address 2ff22ac0
value of pointer 20012ff8
routineC
pointer residing at address 2ff22ac0
value of pointer 20012ff8
Current allocation report:

   Allocation #0: 0x2000EFF8
      Allocation size: 0x4
      Allocation traceback:
      0xD03EA170 malloc
      0xD036C260 init_malloc
      0xD036D434 malloc
      0x10000540 main

   Allocation #1: 0x20010FF8
      Allocation size: 0x4
      Allocation traceback:
      0xD03EA170 malloc
      0x10000360 routineA
      0x1000058C main
      0x100001C4 __start

   Allocation #2: 0x20012FF8
      Allocation size: 0x8
      Allocation traceback:
      0xD03EA170 malloc
      0x100003FC routineC
      0x10000594 main
      0x100001C4 __start

   Total allocations: 3.

The malloc debug subsystem states there are three memory leaks in the program. The first one is the main routine (at address 0x2000EFF8, size 4 bytes), the second one is in routineA (at address 0x20010FF8, size 4 bytes) and the last one is located in routineC (at address 0x20012FF8, size 8 bytes).

Whenever you wish to open a PMR for a memory leak, be sure to add the malloc trace aswell. If it's not a known issue, you will be redirected to L3 support quite fast :)

Geen opmerkingen:

Een reactie posten