Memory profiling using Valgrind
By: Poby S Home
Tags: Profiling, Memory Management, Linux, Memory Leak, Valgrind

Know how much memory you are consuming.

What is Valgrind?

Valgrind is a flexible program for debugging and profiling Linux executables. Most important usage of valgrind is when you try to find memory leaks.

Download valgrind

$ sudo apt-get install valgrind

How to use a Valgrind

you can choose what tool you want to use with Valgrind. I explain only memcheck and massif which are mostly used and important.

--tool=<toolname> [default: memcheck]

Run the Valgrind tool called toolname,

e.g. memcheck, cachegrind, callgrind, helgrind, drd, massif, lackey, none, exp-sgcheck,exp-bbv, exp-dhat, etc.

memcheck

Memcheck is a memory error detector. It can detect the following problems that are common in C and C++ programs.

Accessing memory you shouldn’t:

e.g. overrunning and underrunning heap blocks, overrunning the top of the stack, and accessing memory after it has been freed.

e.g. overrunning and underrunning heap blocks, overrunning the top of the stack, and accessing memory after it has been freed. Using undefined values:

i.e. values that have not been initialised, or that have been derived from other undefined values.

i.e. values that have not been initialised, or that have been derived from other undefined values. Incorrect freeing of heap memory:

such as double-freeing heap blocks, or mismatched use of malloc/new/new[] versus free/delete/delete[]

such as double-freeing heap blocks, or mismatched use of malloc/new/new[] versus free/delete/delete[] Overlapping src and dst pointers in memcpy and related functions .

. Passing a fishy (presumably negative) value to the size parameter of a memory allocation function .

. Memory leaks.

massif

Massif is a heap profiler. It measures how much heap memory your program uses. This includes both the useful space, and the extra bytes allocated for book-keeping and alignment purposes. It can also measure the size of your program’s stack(s), although it does not do so by default.

In summary, it can give you information about:

Heap blocks

Heap administration blocks

Stack sizes.

Run for a real use case

Memory leak example

#include <unistd.h>

using namespace std; int main()

{

while(true) {

int* a = new int[100];

sleep(1);

}

}

Run valigrind to check memory leak

$ valgrind --tool=memcheck --leak-check=yes --leak-check=full --show-leak-kinds=all -v ./a.out

Ctrl+C and then, a result shows up

^C==11001==

==11001== Process terminating with default action of signal 2 (SIGINT)

==11001== at 0x5303A04: nanosleep (nanosleep.c:28)

==11001== by 0x5303909: sleep (sleep.c:55)

==11001== by 0x1086E9: main (in /home/poby/ProgramingPractice/C++/a.out)

--11001-- REDIR: 0x52b69c0 (libc.so.6:free) redirected to 0x4c30cd0 (free)

==11001==

==11001== HEAP SUMMARY:

==11001== in use at exit: 4,400 bytes in 11 blocks

==11001== total heap usage: 12 allocs, 1 frees, 77,104 bytes allocated

==11001==

==11001== Searching for pointers to 11 not-freed blocks

==11001== Checked 110,848 bytes

==11001==

==11001== 400 bytes in 1 blocks are still reachable in loss record 1 of 2

==11001== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==11001== by 0x1086DB: main (in /home/poby/ProgramingPractice/C++/a.out)

==11001==

==11001== 4,000 bytes in 10 blocks are definitely lost in loss record 2 of 2

==11001== at 0x4C3089F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==11001== by 0x1086DB: main (in /home/poby/ProgramingPractice/C++/a.out)

==11001==

==11001== LEAK SUMMARY:

==11001== definitely lost: 4,000 bytes in 10 blocks

==11001== indirectly lost: 0 bytes in 0 blocks

==11001== possibly lost: 0 bytes in 0 blocks

==11001== still reachable: 400 bytes in 1 blocks

==11001== suppressed: 0 bytes in 0 blocks

==11001==

==11001== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

==11001== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

As you can see, it reports where it is leaking and how much it is leaking.

check heap and stack with massif

$ valgrind --tool=massif --stacks=yes --log-file=valgrind.log ./a.out

running valgrind with above will create two files, one massif.out.xxx file and the other valgrind.log file.

Text visualization of massif.out file

$ ms_print massif.out.11686

--------------------------------------------------------------------------------

Command: ./a.out

Massif arguments: --stacks=yes

ms_print arguments: massif.out.11686

-------------------------------------------------------------------------------- KB

89.23^ #

| ... #

| @@ #

0 +----------------------------------------------------------------------->Mi

0 2.069 Number of snapshots: 57

Detailed snapshots: [1, 14, 26, 38, 49, 50, 51, 52, 53, 54, 55, 56 (peak)] --------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

0 0 0 0 0 0

1 39,481 7,176 0 0 7,176

00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. --------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

2 100,934 1,096 0 0 1,096

3 139,912 1,568 0 0 ... 14 656,626 1,416 0 0 1,416

00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. --------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

15 695,856 1,320 0 0 1,320

16 724,630 1,320 0 0

... 26 1,202,021 1,320 0 0 1,320

00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. --------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

27 1,256,763 1,576 0 0 1,576

...

38 1,726,816 1,320 0 0 1,320

00.00% (0B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. --------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

39 1,778,582 1,576 0 0 1,576

...

49 2,167,678 82,008 81,504 184 320

99.39% (81,504B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->88.65% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->88.65% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->88.65% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->10.73% (8,800B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

50 2,167,894 83,232 82,704 208 320

99.37% (82,704B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->87.35% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->87.35% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->87.35% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->12.01% (10,000B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

51 2,168,110 84,456 83,904 232 320

99.35% (83,904B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->86.09% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->86.09% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->86.09% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->13.26% (11,200B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

52 2,168,326 85,680 85,104 256 320

99.33% (85,104B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->84.86% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->84.86% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->84.86% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->14.47% (12,400B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

53 2,168,542 86,904 86,304 280 320

99.31% (86,304B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->83.66% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->83.66% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->83.66% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->15.65% (13,600B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

54 2,168,758 88,128 87,504 304 320

99.29% (87,504B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->82.50% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->82.50% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->82.50% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->16.79% (14,800B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

55 2,168,974 89,352 88,704 328 320

99.27% (88,704B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->81.37% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->81.37% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->81.37% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->17.91% (16,000B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)



--------------------------------------------------------------------------------

n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)

--------------------------------------------------------------------------------

56 2,169,387 91,368 89,104 336 1,928

97.52% (89,104B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.

->79.57% (72,704B) 0x4ED4974: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.26)

| ->79.57% (72,704B) 0x4010781: _dl_init (dl-init.c:72)

| ->79.57% (72,704B) 0x40010C8: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)

|

->17.95% (16,400B) 0x1086DA: main (in /home/poby/ProgramingPractice/C++/a.out)

graphical visualization with massif-visualizer

ms_print is not very easy to look with a lot of text. Use massif-visualizer to get a better view.