Qt-interest Archive, March 2007
Memory leak in QSettings
Message 1 in thread
QSettings class produces a memory leak when c'tor is called.
QSettings::QSettings(Format format, Scope scope, const QString
&organization, const QString &application, QObject *parent)
: QObject(*QSettingsPrivate::create(format, scope, organization,
application), parent)
the refererenced pointer created by QSettingsPrivate::create is just
passed to the QObject and no one owes it any more which eventually leads
to a memleak.
I think this behavior is somehow by design, however it produces lots of
nasty memleak reports.
--
[ signature omitted ]
Message 2 in thread
On Monday, 5. March 2007 15:35, Andrei Korostelev wrote:
> QSettings class produces a memory leak when c'tor is called.
>
> QSettings::QSettings(Format format, Scope scope, const QString
> &organization, const QString &application, QObject *parent)
>
> : QObject(*QSettingsPrivate::create(format, scope, organization,
>
> application), parent)
This constructor allocates sets the d pointer.
> the refererenced pointer created by QSettingsPrivate::create is just
> passed to the QObject and no one owes it any more which eventually leads
> to a memleak.
The d pointer is owned by the QSettings object and is deleted in the QObject
destructor. So I don't think this will cause a memory leak.
-Rainer
--
[ signature omitted ]
Message 3 in thread
Rainer Sabelka wrote:
> The d pointer is owned by the QSettings object and is deleted in the QObject
> destructor. So I don't think this will cause a memory leak.
>
> -Rainer
I looked into it more detailed. You are right in the sense that the leak
was not caused by ::operator new for storing QSettingsPrivate pointer as
such, it was a couple of stack frames deeper.
Here is a minimal code for MSVS 2005 console app.
#include <QSettings>
#define HUNT_FOR_MEM_LEAKS
#if defined(WIN32) && defined (HUNT_FOR_MEM_LEAKS)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
int main(int argc, char *argv[])
{
#if defined(WIN32) && defined (HUNT_FOR_MEM_LEAKS)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
#endif
{
QSettings mySettings(QSettings::IniFormat, QSettings::UserScope,
"MyCompany", "MyApp");
}
return 0;
}
The output is:
Detected memory leaks!
Dumping objects ->
{393} normal block at 0x0039BDF8, 20 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 CD CD CD
{392} normal block at 0x0039BD70, 92 bytes long.
Data: < g8 9 3#g> C4 F4 18 67 38 BD 39 00 00 00 00 00 B4 33 23 67
{391} normal block at 0x0039BD38, 8 bytes long.
Data: < gp 9 > D0 F4 18 67 70 BD 39 00
{390} normal block at 0x0039BCF8, 20 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 CD CD CD
{389} normal block at 0x0039BCA0, 40 bytes long.
Data: < 8 9 > 01 00 00 00 38 BD 39 00 00 CD CD CD 00 00 00 00
{188} normal block at 0x00396CE8, 56 bytes long.
Data: < , . ; % > 1E 00 00 00 97 00 00 00 2C 00 2E 00 3B 00 25 00
{187} normal block at 0x00396CB8, 4 bytes long.
Data: < g> A0 FF 18 67
Object dump complete.
I looked into the block 187 for example, the memory allocation was in:
void QLocalePrivate::updateSystemPrivate()
{
if (!system_lp)
system_lp = new QLocalePrivate;
...
The stack dump is the following:
msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=56, int
nBlockUse=1, const char * szFileName=0x00000000, int nLine=0) Line
369 C++
msvcr80d.dll!_nh_malloc_dbg(unsigned int nSize=56, int nhFlag=0,
int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0) Line
266 + 0x15 bytes C++
msvcr80d.dll!malloc(unsigned int nSize=56) Line 152 + 0x15
bytes C++
msvcr80d.dll!operator new(unsigned int size=56) Line 59 + 0x9
bytes C++
> QtCored4.dll!QLocalePrivate::updateSystemPrivate() Line 1203 +
0x7 bytes C++
QtCored4.dll!systemPrivate() Line 1239 C++
QtCored4.dll!defaultPrivate() Line 1248 + 0x5 bytes C++
QtCored4.dll!QLocale::QLocale() Line 1947 + 0x5 bytes C++
QtCored4.dll!QResourceFileEnginePrivate::QResourceFileEnginePrivate()
Line 994 + 0x59 bytes C++
QtCored4.dll!QResourceFileEngine::QResourceFileEngine(const QString
& file={...}) Line 1059 + 0x4a bytes C++
QtCored4.dll!QResourceFileEngineHandler::create(const QString &
path={...}) Line 980 + 0x26 bytes C++
QtCored4.dll!QAbstractFileEngine::create(const QString &
fileName={...}) Line 179 + 0x26 bytes C++
QtCored4.dll!QFileInfoPrivate::initFileEngine(const QString &
file={...}) Line 116 + 0x9 bytes C++
QtCored4.dll!QFileInfo::QFileInfo(const QString & file={...}) Line
373 C++
QtCored4.dll!QFile::exists(const QString & fileName={...}) Line
511 + 0xc bytes C++
QtCored4.dll!QLibraryInfoPrivate::findConfiguration() Line 97 +
0x9 bytes C++
QtCored4.dll!QLibrarySettings::QLibrarySettings() Line 84 + 0x5
bytes C++
QtCored4.dll!QLibraryInfoPrivate::qt_library_settings() Line 79 +
0xa1 bytes C++
QtCored4.dll!QLibraryInfoPrivate::configuration() Line 72 + 0x5
bytes C++
QtCored4.dll!QLibraryInfo::location(QLibraryInfo::LibraryLocation
loc=SettingsPath) Line 213 + 0x5 bytes C++
QtCored4.dll!getPath(QSettings::Format format=IniFormat,
QSettings::Scope scope=UserScope) Line 1035 + 0xb bytes C++
QtCored4.dll!QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format
format=IniFormat, QSettings::Scope scope=UserScope, const QString &
organization={...}, const QString & application={...}) Line 1111 + 0xf
bytes C++
QtCored4.dll!QSettingsPrivate::create(QSettings::Format
format=IniFormat, QSettings::Scope scope=UserScope, const QString &
organization={...}, const QString & application={...}) Line 893 + 0x32
bytes C++
QtCored4.dll!QSettings::QSettings(QSettings::Format
format=IniFormat, QSettings::Scope scope=UserScope, const QString &
organization={...}, const QString & application={...}, QObject *
parent=0x00000000) Line 2499 + 0x20 bytes C++
TestQt.exe!main(int argc=1, char * * argv=0x00393a68) Line 19 +
0x3e bytes C++
TestQt.exe!__tmainCRTStartup() Line 586 + 0x19 bytes C
TestQt.exe!mainCRTStartup() Line 403 C
kernel32.dll!7c816fd7()
-- Andrei
Message 4 in thread
Hi,
> if (!system_lp)
> system_lp = new QLocalePrivate;
Did you check that system_lp was not static ? If it is static, then
there is no memory leak.
Matthieu
--
[ signature omitted ]
Message 5 in thread
Matthieu Brucher wrote:
>> if (!system_lp)
>> system_lp = new QLocalePrivate;
>
> Did you check that system_lp was not static ? If it is static, then
> there is no memory leak.
>
> Matthieu
He-he, I did not check it, I was writing this in haste. Yes, it's indeed
has static life duration ;-)
Therefore the problem turns into the following: I need somehow to
separate Qt leaks from other leaks, so that the former would not appear
into the memleaks report.
Any ideas? (for Windows/MSVC at least).
--
[ signature omitted ]
Message 6 in thread
On 05.03.07 19:16:19, Andrei Korostelev wrote:
> Matthieu Brucher wrote:
> >> if (!system_lp)
> >> system_lp = new QLocalePrivate;
> >
> >Did you check that system_lp was not static ? If it is static, then there is
> >no memory leak.
> >
> >Matthieu
> He-he, I did not check it, I was writing this in haste. Yes, it's indeed has
> static life duration ;-)
>
> Therefore the problem turns into the following: I need somehow to separate Qt
> leaks from other leaks, so that the former would not appear into the memleaks
> report.
> Any ideas? (for Windows/MSVC at least).
When a memleak is "found" you have to check wether its a false positive
or not, if your memleak-checking tool is not smart enough (not sure if
such a tool can be smart enough to detect cases as this one, though)
Andreas
--
[ signature omitted ]
Message 7 in thread
Andreas Pakulat wrote:
> On 05.03.07 19:16:19, Andrei Korostelev wrote:
>
>> The problem turns into the following: I need somehow to separate Qt
>> leaks from other leaks, so that the former would not appear into the memleaks
>> report.
>> Any ideas? (for Windows/MSVC at least).
>>
>
> When a memleak is "found" you have to check wether its a false positive
> or not, if your memleak-checking tool is not smart enough (not sure if
> such a tool can be smart enough to detect cases as this one, though)
>
> Andreas
>
In Windows I do not use external tools to hunt for memleaks.
Instead, at compile-timle I redifine heap allocation functions with a
macro, which tracks down allocation requests (for details you can have a
look at one of my previous post to this thread). What I can think of is
probably a similar macro in Qt. But apparently nothing of this sort
exists ;(
Message 8 in thread
Hi,
> What I can think of is probably a similar macro in Qt. But apparently nothing of this sort
> exists ;(
There are already specialized tools for memory debugging out there :
Purify, Insure++, Valgrind... Trolltech does currently not sell such tools.
--
[ signature omitted ]
Message 9 in thread
Dimitri wrote:
> Hi,
>
>> What I can think of is probably a similar macro in Qt. But apparently
>> nothing of this sort exists ;(
>
> There are already specialized tools for memory debugging out there :
> Purify, Insure++, Valgrind... Trolltech does currently not sell such
> tools.
>
> --
> Dimitri
>
I know about these tools. The funny thing is that I were just happy
using this easy and cheap compiled-in "macro-way" to discover memleaks
up to the point we started using Qt in our project. And now we will have
to consider another way. ;-/
--Andrei
--
[ signature omitted ]
Message 10 in thread
Hi,
> I know about these tools. The funny thing is that I were just happy
> using this easy and cheap compiled-in "macro-way" to discover memleaks
> up to the point we started using Qt in our project. And now we will have
> to consider another way. ;-/
It's hard to make good memory debuggers. One common issue with "easy and
cheap" tools : memory may be released after main() has returned (in
static object destructors for example) and this may be flagged as a
memory leak. I think many macro-based "easy and cheap" tools do not
handle this. Even the tool bundled with Visual Studio used not to (or
does not) handle this.
--
[ signature omitted ]
Message 11 in thread
Dimitri wrote:
> Hi,
>
>> I know about these tools. The funny thing is that I were just happy
>> using this easy and cheap compiled-in "macro-way" to discover
>> memleaks up to the point we started using Qt in our project. And now
>> we will have to consider another way. ;-/
>
> It's hard to make good memory debuggers. One common issue with "easy
> and cheap" tools : memory may be released after main() has returned
> (in static object destructors for example) and this may be flagged as
> a memory leak.
>
Well, you can always make a clean-up function for static objects and
pass it to atexit(), which is executed before the statics get destroyed.
I'd prefer Qt statics destroyed the same way.
However it seems Qt developers decided not to complicate the things and
let the compiler decide when statics can go away.
--Andrei
--
[ signature omitted ]
Message 12 in thread
Hi,
> Well, you can always make a clean-up function for static objects and
> pass it to atexit(), which is executed before the statics get destroyed.
> I'd prefer Qt statics destroyed the same way.
This doesn't work with DLLs though.
--
[ signature omitted ]
Message 13 in thread
Hi,
> Hi,
>
>> Well, you can always make a clean-up function for static objects and
>> pass it to atexit(), which is executed before the statics get
>> destroyed. I'd prefer Qt statics destroyed the same way.
>
> This doesn't work with DLLs though.
>
Hm, why? It works both for static and dynamic libraries. For dynamic
libs it works both for implicit and explicit load (i.e. with
LoadLibrary/dlopen) - atexit is called once the library is unloaded.
The only ugly thing I can think of is using both implicit and explicit
library load within the same client application.
--Andrei
--
[ signature omitted ]
Message 14 in thread
On 05.03.07 21:51:35, Andrei Korostelev wrote:
> Dimitri wrote:
> >Hi,
> >
> >>What I can think of is probably a similar macro in Qt. But apparently nothing
> >>of this sort exists ;(
> >
> >There are already specialized tools for memory debugging out there : Purify,
> >Insure++, Valgrind... Trolltech does currently not sell such tools.
> >
> >--
> >Dimitri
> >
> I know about these tools. The funny thing is that I were just happy using this
> easy and cheap compiled-in "macro-way" to discover memleaks up to the point we
> started using Qt in our project. And now we will have to consider another way.
> ;-/
The nice thing about those tools is that you don't need to compile
whatever you want to check.
Andreas
--
[ signature omitted ]
Message 15 in thread
Hi,
> I looked into the block 187 for example, the memory allocation was in:
>
> void QLocalePrivate::updateSystemPrivate()
> {
> if (!system_lp)
> system_lp = new QLocalePrivate;
> ...
This is a static variable. It's allocated once - for the lifespan of the
program.
--
[ signature omitted ]