Previous: Example 9, Up: Examples


16.10 Additional useful information

This last example illustrates the various SHOW options that are available for displaying additional information from the mpatrol library at program termination. It also shows how to easily detect memory leaks. Use the OFLOWSIZE=16, NOFREE=16 and SHOWALL options in MPATROL_OPTIONS before running.

      1  /*
      2   * Introduces a memory leak by clobbering a pointer with a new
      3   * memory allocation.  Use with SHOWUNFREED to display it.
      4   */
     
     
      7  #include "mpatrol.h"
     
     
     10  int main(void)
     11  {
     12      void *p;
     
     14      p = malloc(4);
     15      p = malloc(4);
     16      if (p != NULL)
     17          free(p);
     18      return EXIT_SUCCESS;
     19  }

The information that we are interested in comes after the summary of library statistics generated in the log file. The first block of data shows a memory map of the heap that is being handled by mpatrol. This can be used to see graphically where a particular allocation is located, or to look for memory fragmentation. The SHOWMAP option also displays this information.

Note that gaps in the memory map can either be due to space used by internal memory blocks or to some other memory allocation library using up space. On some systems that don't have virtual memory, gaps are likely to be owned by other processes or belong to the system free memory list. The `...' marks text that has been removed.

     memory map:
         ...
       / 0x0002FDD0-0x0002FDDF overflow (16 bytes)
      |+ 0x0002FDE0-0x0002FE03 allocated (36 bytes) {calloc:13:0} [-|-|-]
       \ 0x0002FE04-0x0002FE13 overflow (16 bytes)
     --- 0x0002FE14-0x0002FE17 free (4 bytes)
       / 0x0002FE18-0x0002FE27 overflow (16 bytes)
      |+ 0x0002FE28-0x0002FF18 allocated (241 bytes) {calloc:15:0} [-|-|-]
       \ 0x0002FF19-0x0002FF28 overflow (16 bytes)
     --- 0x0002FF29-0x0002FF2F free (7 bytes)
       / 0x0002FF30-0x0002FF3F overflow (16 bytes)
      |+ 0x0002FF40-0x0002FF93 allocated (84 bytes) {calloc:16:0} [-|-|-]
       \ 0x0002FF94-0x0002FFA3 overflow (16 bytes)
     --- 0x0002FFA4-0x0002FFA7 free (4 bytes)
       / 0x0002FFA8-0x0002FFB7 overflow (16 bytes)
      |+ 0x0002FFB8-0x0002FFC4 allocated (13 bytes) {calloc:17:0} [-|-|-]
       \ 0x0002FFC5-0x0002FFD4 overflow (16 bytes)
     --- 0x0002FFD5-0x0002FFD7 free (3 bytes)
       / 0x0002FFD8-0x0002FFE7 overflow (16 bytes)
      |+ 0x0002FFE8-0x0002FFEB allocated (4 bytes) {malloc:19:0} [main|test.c|14]
       \ 0x0002FFEC-0x0002FFFB overflow (16 bytes)
     --- 0x0002FFFC-0x0002FFFF free (4 bytes)
         --------------------- gap (57344 bytes)
       / 0x0003E000-0x0003E00F overflow (16 bytes)
      |+ 0x0003E010-0x0003EFFF freed (4080 bytes) {free:6:0} [-|-|-]
       \ 0x0003F000-0x0003F00F overflow (16 bytes)
       / 0x0003F010-0x0003F01F overflow (16 bytes)
      |+ 0x0003F020-0x0003F707 freed (1768 bytes) {free:12:0} [-|-|-]
       \ 0x0003F708-0x0003F717 overflow (16 bytes)
     --- 0x0003F718-0x0003FFFF free (2280 bytes)
         --------------------- gap (16384 bytes)
       / 0x00044000-0x0004400F overflow (16 bytes)
      |+ 0x00044010-0x00045197 freed (4488 bytes) {free:8:0} [-|-|-]
       \ 0x00045198-0x000451A7 overflow (16 bytes)
       / 0x000451A8-0x000451B7 overflow (16 bytes)
      |+ 0x000451B8-0x000459AF freed (2040 bytes) {free:10:0} [-|-|-]
       \ 0x000459B0-0x000459BF overflow (16 bytes)
       / 0x000459C0-0x000459CF overflow (16 bytes)
      |+ 0x000459D0-0x00045D93 allocated (964 bytes) {calloc:14:0} [-|-|-]
       \ 0x00045D94-0x00045DA3 overflow (16 bytes)
       / 0x00045DA4-0x00045DB3 overflow (16 bytes)
      |+ 0x00045DB4-0x00045DCE allocated (27 bytes) {strdup:18:0} [-|-|-]
       \ 0x00045DCF-0x00045DDE overflow (16 bytes)
     --- 0x00045DDF-0x00045DDF free (1 byte)
       / 0x00045DE0-0x00045DEF overflow (16 bytes)
      |+ 0x00045DF0-0x00045DF3 freed (4 bytes) {free:20:0} [main|test.c|17]
       \ 0x00045DF4-0x00045E03 overflow (16 bytes)
     --- 0x00045E04-0x00045FFF free (508 bytes)

The next block of data shows a summary of all the symbols that could be read from the program's executable file and/or any shared libraries that the program requires. This can be useful to see which symbols have actually been read by the mpatrol library. The SHOWSYMBOLS option also displays this information.

Note that the following data has been dramatically cut down in size for the purposes of this example. The `...' marks text that has been removed.

     symbols read: 3300
                    0x000108B0 _ex_text0 [a.out] (0 bytes)
         0x000108B0-0x0001097F _start [a.out] (208 bytes)
         0x00010990-0x00010A27 main [a.out] (152 bytes)
                    0x00010A28 _ex_text1 [a.out] (0 bytes)
         0x00010A28-0x00010A77 _init [a.out] (80 bytes)
         0x00010A78-0x00010AC7 _fini [a.out] (80 bytes)
                    0x7FA1FFF8 _ex_text0 [/usr/lib/libc.so.1] (0 bytes)
         0x7FA1FFF8-0x7FA2005F atexit [/usr/lib/libc.so.1] (104 bytes)
         0x7FA20060-0x7FA200EF _exithandle [/usr/lib/libc.so.1] (144 bytes)
         0x7FA20470-0x7FA204EB __dtou [/usr/lib/libc.so.1] (124 bytes)
         0x7FA20500-0x7FA20577 __ftou [/usr/lib/libc.so.1] (120 bytes)
         0x7FA2083C-0x7FA20B2F __div64 [/usr/lib/libc.so.1] (756 bytes)
         0x7FA20B30-0x7FA20DEB __rem64 [/usr/lib/libc.so.1] (700 bytes)
         ...
         0x7FA96858-0x7FA96867 getpid [/usr/lib/libc.so.1] (16 bytes)
         0x7FA96858-0x7FA96867 _getpid [/usr/lib/libc.so.1] (16 bytes)
         0x7FA96868-0x7FA9689F _kill [/usr/lib/libc.so.1] (56 bytes)
         0x7FA96868-0x7FA9689F _libc_kill [/usr/lib/libc.so.1] (56 bytes)
                    0x7FA968A0 _ex_text1 [/usr/lib/libc.so.1] (0 bytes)
         0x7FA968A0-0x7FA968DF _init [/usr/lib/libc.so.1] (64 bytes)
         0x7FA968E0-0x7FA9691F _fini [/usr/lib/libc.so.1] (64 bytes)
         0x7FB105E4-0x7FB1069F memmove [/usr/lib/libc_psr.so.1] (188 bytes)
         0x7FB105E4-0x7FB1069F _memmove [/usr/lib/libc_psr.so.1] (188 bytes)
                    0x7FB106A0 forcpy [/usr/lib/libc_psr.so.1] (0 bytes)
         0x7FB106A0-0x7FB1190B memcpy [/usr/lib/libc_psr.so.1] (4716 bytes)
         0x7FB106A0-0x7FB1190B _memcpy [/usr/lib/libc_psr.so.1] (4716 bytes)
         0x7FB106A0-0x7FB1190B __align_cpy_1 [/usr/lib/libc_psr.so.1] (4716 bytes)
         ...
         0x7FB135B0-0x7FB135D3 __div64 [/usr/lib/libc_psr.so.1] (36 bytes)
         0x7FB135D4-0x7FB135F7 __udiv64 [/usr/lib/libc_psr.so.1] (36 bytes)
         0x7FB135F8-0x7FB1362B __umul64 [/usr/lib/libc_psr.so.1] (52 bytes)
         0x7FB135F8-0x7FB1362B __mul64 [/usr/lib/libc_psr.so.1] (52 bytes)
         0x7FB1362C-0x7FB13657 __urem64 [/usr/lib/libc_psr.so.1] (44 bytes)
         0x7FB13658-0x7FB13683 __rem64 [/usr/lib/libc_psr.so.1] (44 bytes)
                    0x7FB333F8 _ex_text0 [/usr/lib/libelf.so.1] (0 bytes)
         0x7FB333F8-0x7FB3346F _elf32_entsz [/usr/lib/libelf.so.1] (120 bytes)
         0x7FB33470-0x7FB334EB elf32_fsize [/usr/lib/libelf.so.1] (124 bytes)
         0x7FB33470-0x7FB334EB _elf32_fsize [/usr/lib/libelf.so.1] (124 bytes)
         0x7FB334EC-0x7FB3352F _elf32_msize [/usr/lib/libelf.so.1] (68 bytes)
         0x7FB33530-0x7FB335D3 _elf32_mtype [/usr/lib/libelf.so.1] (164 bytes)
         ...
         0x7FB49054-0x7FB4921F _elf_nlist [/usr/lib/libelf.so.1] (460 bytes)
         0x7FB49220-0x7FB4932F nlist [/usr/lib/libelf.so.1] (272 bytes)
         0x7FB49330-0x7FB493E3 _elf_findop [/usr/lib/libelf.so.1] (180 bytes)
                    0x7FB493E4 _ex_text1 [/usr/lib/libelf.so.1] (0 bytes)
         0x7FB493E4-0x7FB4941B _init [/usr/lib/libelf.so.1] (56 bytes)
         0x7FB4941C-0x7FB49453 _fini [/usr/lib/libelf.so.1] (56 bytes)
         0x7FB65818-0x7FB6582F __mp_newlist [/usr/lib/libmpatrol.so.1.3] (24 bytes)
         0x7FB65830-0x7FB65853 __mp_addhead [/usr/lib/libmpatrol.so.1.3] (36 bytes)
         0x7FB65854-0x7FB6587B __mp_addtail [/usr/lib/libmpatrol.so.1.3] (40 bytes)
         0x7FB6587C-0x7FB6589F __mp_prepend [/usr/lib/libmpatrol.so.1.3] (36 bytes)
         0x7FB658A0-0x7FB658C3 __mp_insert [/usr/lib/libmpatrol.so.1.3] (36 bytes)
         0x7FB658C4-0x7FB658EB __mp_remove [/usr/lib/libmpatrol.so.1.3] (40 bytes)
         ...
         0x7FB725F4-0x7FB7262B memmem [/usr/lib/libmpatrol.so.1.3] (56 bytes)
         0x7FB7262C-0x7FB72663 _memmem [/usr/lib/libmpatrol.so.1.3] (56 bytes)
         0x7FB72664-0x7FB72697 memcmp [/usr/lib/libmpatrol.so.1.3] (52 bytes)
         0x7FB72698-0x7FB726CB _memcmp [/usr/lib/libmpatrol.so.1.3] (52 bytes)
         0x7FB726CC-0x7FB726FF bcmp [/usr/lib/libmpatrol.so.1.3] (52 bytes)
         0x7FB72700-0x7FB72733 _bcmp [/usr/lib/libmpatrol.so.1.3] (52 bytes)
         0x7FB9085C-0x7FB90863 dlinfo [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB9085C-0x7FB90863 _dlinfo [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB90864-0x7FB9086B dlmap [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB90864-0x7FB9086B _dlmap [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB9086C-0x7FB90873 dlmopen [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB9086C-0x7FB90873 _dlmopen [/usr/lib/libdl.so.1] (8 bytes)
         ...
         0x7FB90894-0x7FB9089B dladdr [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB90894-0x7FB9089B _dladdr [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB9089C-0x7FB908A3 dldump [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB9089C-0x7FB908A3 _dldump [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB908A4-0x7FB908AB _ld_concurrency [/usr/lib/libdl.so.1] (8 bytes)
         0x7FB908AC-0x7FB908B3 bind_guard [/usr/lib/libdl.so.1] (8 bytes)

The next table is really only useful for seeing how much memory fragmentation has occurred in the memory map. It shows a breakdown of the free memory blocks that have either resulted from the mpatrol library allocating uninitialised memory from the system heap or from freeing existing memory allocations. The column on the left shows the size of the free block in bytes and the column on the right shows the number of blocks of that size that are available. The SHOWFREE option also displays this information.

     free blocks: 10 (2919 bytes)
            2280: 1
             508: 1
              76: 1
              32: 1
               7: 1
               4: 3
               3: 1
               1: 1

The next block of data shows a summary of all freed memory allocations. This is only possible because the NOFREE option was also given, otherwise there would be no details on freed memory allocations. All of these entries show where the allocation was freed, which can be useful if you quickly needed to see where an allocation was freed. The SHOWFREED option also displays this information. Note that the list will be limited to the size of the freed queue and will show only the most recently-freed items.

As this example was run on UNIX, the mpatrol library replaces the default implementations of malloc(), free(), etc. As can be seen below, this allows the library to trace all calls to allocate dynamic memory in a process, even from functions that were not compiled with mpatrol. Four of the five functions shown below were called by the mpatrol library in order to read the symbols from ELF object files. However, they are located in the ELF access library which was not compiled with mpatrol.

Note that the following data has again been cut down in size for the purposes of this example. The `...' marks text that has been removed.

     freed allocations: 13 (19756 bytes)
         0x0002E010 (232 bytes) {free:1:0} [-|-|-]
             0x7FB3E5BC _elf_end+776
             0x7FB6B3D4 __mp_addsymbols+440
             0x7FB6FF5C __mp_init+208
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002E118 (3536 bytes) {free:2:0} [-|-|-]
             0x7FB3E450 _elf_end+412
             0x7FB6B3D4 __mp_addsymbols+440
             0x7FB6FF5C __mp_init+208
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002EF08 (232 bytes) {free:3:0} [-|-|-]
             0x7FB3E5BC _elf_end+776
             0x7FB6B3D4 __mp_addsymbols+440
             0x7FB6B4B4 __mp_addextsymbols+208
             0x7FB6FF64 __mp_init+216
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002F010 (2448 bytes) {free:4:0} [-|-|-]
             0x7FB3E450 _elf_end+412
             0x7FB6B3D4 __mp_addsymbols+440
             0x7FB6B4B4 __mp_addextsymbols+208
             0x7FB6FF64 __mp_init+216
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         ...
     
         0x00045DF0 (4 bytes) {free:20:0} [main|test.c|17]
             0x00010A14 main+132
             0x00010970 _start+192

The final block of data shows a summary of all unfreed memory allocations. This can show up memory leaks, although all but one of the unfreed memory allocations in this example come from the standard C library. On systems such as UNIX it does not really matter about these unfreed allocations since they will automatically be returned to the system on process termination.

However, the other unfreed allocation shows an example of a memory leak, where no pointers referencing that allocation remain in the program to free it with. If this was within a loop then the program could quickly run away with memory, causing at least a decrease in performance, and at most a memory shortage. The mpatrol library makes it easier to spot memory leaks, especially if the PROF profiling option is used.

The SHOWUNFREED option also displays this information.

     unfreed allocations: 7 (1369 bytes)
         0x0002FDE0 (36 bytes) {calloc:13:0} [-|-|-]
             0x7FA54B7C _tzload+56
             0x7FA53990 _ltzset_u+444
             0x7FA52D98 localtime_u+28
             0x7FA3AF20 ctime+12
             0x7FB6D05C __mp_printversion+184
             0x7FB6FFA0 __mp_init+276
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002FE28 (241 bytes) {calloc:15:0} [-|-|-]
             0x7FA54E3C _tzload+760
             0x7FA53990 _ltzset_u+444
             0x7FA52D98 localtime_u+28
             0x7FA3AF20 ctime+12
             0x7FB6D05C __mp_printversion+184
             0x7FB6FFA0 __mp_init+276
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002FF40 (84 bytes) {calloc:16:0} [-|-|-]
             0x7FA54E64 _tzload+800
             0x7FA53990 _ltzset_u+444
             0x7FA52D98 localtime_u+28
             0x7FA3AF20 ctime+12
             0x7FB6D05C __mp_printversion+184
             0x7FB6FFA0 __mp_init+276
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002FFB8 (13 bytes) {calloc:17:0} [-|-|-]
             0x7FA54EE8 _tzload+932
             0x7FA53990 _ltzset_u+444
             0x7FA52D98 localtime_u+28
             0x7FA3AF20 ctime+12
             0x7FB6D05C __mp_printversion+184
             0x7FB6FFA0 __mp_init+276
             0x7FB701FC __mp_alloc+84
             0x000109B8 main+40
             0x00010970 _start+192
     
         0x0002FFE8 (4 bytes) {malloc:19:0} [main|test.c|14]
             0x000109B8 main+40
             0x00010970 _start+192
     
         ...

Beginning with mpatrol release 1.4.2, the LEAKTABLE option is available to summarise the above unfreed memory allocations without including the internal memory allocations that were made when the mpatrol library was initialised. If you add the LEAKTABLE option to the MPATROL_OPTIONS environment variable and then re-run the program you should see the following in the mpatrol log file:

     top 1 unfreed memory entry in leak table:
     
            bytes   count  location
         --------  ------  --------
                4       1  test.c line 14
                4       1  total