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:
- How I can detect memory leaks of C++ application in Linux (Ubuntu OS)?
- How to check for memory leaks in a large scale c++ Linux application?
- Still Reachable Leak detected by Valgrind
- With Memcheck’s memory leak detector, what’s the difference between “definitely lost”, “indirectly lost”, “possibly lost”, “still reachable”, and “suppressed”?
- 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)));
}
Detecting leaks on Windows
Just in case if you need to detect leaks on Windows (where Valgrind doesn’t work and will never work by design), give Deleaker a try. By the way it can be integrated with Qt Creator, see video on YouTube.