Detecting memory leaks of C++ application in Ubuntu

First, I tried Valgrind tool using the following command:

valgrind --tool=memcheck --leak-check=yes ./app

With some large QT application started for some short period I got the following output:

==7090== HEAP SUMMARY:
==7090==     in use at exit: 5,623,365 bytes in 36,268 blocks
==7090==   total heap usage: 32,454,680 allocs, 32,418,412 frees, 12,822,939,874 bytes allocated
…………………………..
==7090== LEAK SUMMARY:
==7090== definitely lost: 20,163 bytes in 74 blocks
==7090== indirectly lost: 60,053 bytes in 1,273 blocks
==7090== possibly lost: 396,167 bytes in 2,169 blocks
==7090== still reachable: 4,834,822 bytes in 31,576 blocks
==7090== suppressed: 0 bytes in 0 blocks
==7090== Reachable blocks (those to which a pointer was found) are not shown.
==7090== To see them, rerun with: –leak-check=full –show-leak-kinds=all
==7090==
==7090== For counts of detected and suppressed errors, rerun with: -v
==7090== Use –track-origins=yes to see where uninitialised values come from
==7090== ERROR SUMMARY: 20905 errors from 1583 contexts (suppressed: 15 from 2)


When I left this app running for the night (approximately 16 hours), I got the following summary:

==3816== HEAP SUMMARY:
==3816==     in use at exit: 7,746,701 bytes in 36,248 blocks
==3816==   total heap usage: 827,800,342 allocs, 827,764,094 frees, 105,404,761,516 bytes allocated
…………………………….
==3816== LEAK SUMMARY:
==3816== definitely lost: 19,835 bytes in 38 blocks
==3816== indirectly lost: 59,805 bytes in 1,237 blocks
==3816== possibly lost: 396,167 bytes in 2,169 blocks
==3816== still reachable: 6,958,734 bytes in 31,628 blocks
==3816== suppressed: 0 bytes in 0 blocks
==3816== Reachable blocks (those to which a pointer was found) are not shown.
==3816== To see them, rerun with: –leak-check=full –show-leak-kinds=all
==3816==
==3816== For counts of detected and suppressed errors, rerun with: -v
==3816== Use –track-origins=yes to see where uninitialised values come from
==3816== ERROR SUMMARY: 13022 errors from 1574 contexts (suppressed: 10 from 2)

It means that the app leaks about 0.126 MB/hour ( (6958734 – 4834822) / 16 / 1024.0 / 1024.0) and totally for the night 2.02 MB, and probably it is not a leak, because the app has pointers to the allocated memory (it is reachable), but it does not clean exit.

To figure out how it works I built the following trivial program:

int main() 
{
  int *a = new int[100];
}

with debug information and started the tool:

g++ -g -o ex ex.cpp
valgrind --tool=memcheck --leak-check=yes ./ex

In the output the tool shows line number 3 where memory leak is occurred:

==22042== Memcheck, a memory error detector
==22042== Copyright (C) 2002-2013, and GNU GPL’d, by Julian Seward et al.
==22042== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==22042== Command: ./ex
==22042==
==22042==
==22042== HEAP SUMMARY:
==22042==     in use at exit: 73,104 bytes in 2 blocks
==22042==   total heap usage: 2 allocs, 0 frees, 73,104 bytes allocated
==22042==
==22042== 400 bytes in 1 blocks are definitely lost in loss record 1 of 2
==22042==    at 0x4C2B800: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22042==    by 0x40061B: main (ex.cpp:3)
==22042==
==22042== LEAK SUMMARY:
==22042==    definitely lost: 400 bytes in 1 blocks
==22042==    indirectly lost: 0 bytes in 0 blocks
==22042==      possibly lost: 0 bytes in 0 blocks
==22042==    still reachable: 72,704 bytes in 1 blocks
==22042==         suppressed: 0 bytes in 0 blocks
==22042== Reachable blocks (those to which a pointer was found) are not shown.
==22042== To see them, rerun with: –leak-check=full –show-leak-kinds=all
==22042==
==22042== For counts of detected and suppressed errors, rerun with: -v
==22042== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Links:

  1. How I can detect memory leaks of C++ application in Linux (Ubuntu OS)?
  2. How to check for memory leaks in a large scale c++ Linux application?
  3. Still Reachable Leak detected by Valgrind
  4. With Memcheck’s memory leak detector, what’s the difference between “definitely lost”, “indirectly lost”, “possibly lost”, “still reachable”, and “suppressed”?
  5. Valgrind: can possibly lost be treated as definitely lost?

Another alternative is calling mallinfo() function in C++ code. The following code gets something like total heap size of the process:

int usedmem = mallinfo().uordblks;

Using this function I wrote a QT widget that shows memory usage in application status bar:

#include <QLabel>
#include <malloc.h>

class MemoryStatusWidget
        : public QLabel
{
public:
    MemoryStatusWidget(QWidget *parent = nullptr);

public:
    void timerEvent(QTimerEvent *) override;
};

MemoryStatusWidget::MemoryStatusWidget(QWidget* parent)
    : QLabel(parent)

{
    startTimer(1000);
}

void MemoryStatusWidget::timerEvent(QTimerEvent *)
{
    int usedmem = mallinfo().uordblks;

    setText(tr("Memory Usage:%1 MB").arg(QString::number((double)usedmem / (1024 * 1024), 'f', 3)));
}

2 Responses to Detecting memory leaks of C++ application in Ubuntu

  1. dmitriano on May 23, 2017 at 10:20 AM:

    To detect where a segmentation fault happens in a QT application compile QT with GCC sanitize option, disable ASLR (Address space layout randomization or set disable randomization on in GDB), set hardware breakpoint on writing to the suspicious address

  2. dmitriano on September 7, 2017 at 4:54 PM:

    in QT pro file:
    #sanitize_address sanitize_memory sanitize_thread sanitize_undefined
    CONFIG += sanitizer sanitize_address
    QMAKE_LFLAGS += -fuse-ld=gold

    from the command line:
    g++ -fsanitize=address -fno-omit-frame-pointer -fuse-ld=gold main.cpp

    or in QT Creator’s Project->Build page->QMake additional arguments: CONFIG+=sanitizer CONFIG+=sanitize_address QMAKE_LFLAGS+=-fuse-ld=gold
    in QT Creator’s environment variables: ASAN_OPTIONS=halt_on_error=0

    To run CMake with specific GCC version:
    export CC=/usr/bin/gcc
    export CXX=/usr/bin/g++

Leave a Reply

Your email address will not be published. Required fields are marked *