gnatmem UsageThe following example shows the use of gnatmem
on a simple memory-leaking program.
Suppose that we have the following Ada program:
| with Unchecked_Deallocation; procedure Test_Gm is type T is array (1..1000) of Integer; type Ptr is access T; procedure Free is new Unchecked_Deallocation (T, Ptr); A : Ptr; procedure My_Alloc is begin A := new T; end My_Alloc; procedure My_DeAlloc is B : Ptr := A; begin Free (B); end My_DeAlloc; begin My_Alloc; for I in 1 .. 5 loop for J in I .. 5 loop My_Alloc; end loop; My_Dealloc; end loop; end; |
The program needs to be compiled with debugging option and linked with
gmem library:
$ gnatmake -g test_gm -largs -lgmem
Then we execute the program as usual:
$ test_gm
Then gnatmem is invoked simply with
$ gnatmem test_gm
which produces the following output (result may vary on different platforms):
Global information
------------------
Total number of allocations : 18
Total number of deallocations : 5
Final Water Mark (non freed mem) : 53.00 Kilobytes
High Water Mark : 56.90 Kilobytes
Allocation Root # 1
-------------------
Number of non freed allocations : 11
Final Water Mark (non freed mem) : 42.97 Kilobytes
High Water Mark : 46.88 Kilobytes
Backtrace :
test_gm.adb:11 test_gm.my_alloc
Allocation Root # 2
-------------------
Number of non freed allocations : 1
Final Water Mark (non freed mem) : 10.02 Kilobytes
High Water Mark : 10.02 Kilobytes
Backtrace :
s-secsta.adb:81 system.secondary_stack.ss_init
Allocation Root # 3
-------------------
Number of non freed allocations : 1
Final Water Mark (non freed mem) : 12 Bytes
High Water Mark : 12 Bytes
Backtrace :
s-secsta.adb:181 system.secondary_stack.ss_init
Note that the GNAT run time contains itself a certain number of allocations that have no corresponding deallocation, as shown here for root #2 and root #3. This is a normal behavior when the number of non-freed allocations is one, it allocates dynamic data structures that the run time needs for the complete lifetime of the program. Note also that there is only one allocation root in the user program with a single line back trace: test_gm.adb:11 test_gm.my_alloc, whereas a careful analysis of the program shows that 'My_Alloc' is called at 2 different points in the source (line 21 and line 24). If those two allocation roots need to be distinguished, the backtrace depth parameter can be used:
$ gnatmem 3 test_gm
which will give the following output:
Global information
------------------
Total number of allocations : 18
Total number of deallocations : 5
Final Water Mark (non freed mem) : 53.00 Kilobytes
High Water Mark : 56.90 Kilobytes
Allocation Root # 1
-------------------
Number of non freed allocations : 10
Final Water Mark (non freed mem) : 39.06 Kilobytes
High Water Mark : 42.97 Kilobytes
Backtrace :
test_gm.adb:11 test_gm.my_alloc
test_gm.adb:24 test_gm
b_test_gm.c:52 main
Allocation Root # 2
-------------------
Number of non freed allocations : 1
Final Water Mark (non freed mem) : 10.02 Kilobytes
High Water Mark : 10.02 Kilobytes
Backtrace :
s-secsta.adb:81 system.secondary_stack.ss_init
s-secsta.adb:283 <system__secondary_stack___elabb>
b_test_gm.c:33 adainit
Allocation Root # 3
-------------------
Number of non freed allocations : 1
Final Water Mark (non freed mem) : 3.91 Kilobytes
High Water Mark : 3.91 Kilobytes
Backtrace :
test_gm.adb:11 test_gm.my_alloc
test_gm.adb:21 test_gm
b_test_gm.c:52 main
Allocation Root # 4
-------------------
Number of non freed allocations : 1
Final Water Mark (non freed mem) : 12 Bytes
High Water Mark : 12 Bytes
Backtrace :
s-secsta.adb:181 system.secondary_stack.ss_init
s-secsta.adb:283 <system__secondary_stack___elabb>
b_test_gm.c:33 adainit
The allocation root #1 of the first example has been split in 2 roots #1 and #3 thanks to the more precise associated backtrace.