Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

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 ]