Trying to understand a mem leak
I'm working with VLD (Visual Leak Detector), and it detects some mem leaks. I'm trying to understand why this is a mem leak for VLD. It could be a false positive?
The code is very simple:
CGlobalLog* CGlobalLog::m_instance=NULL; //static instance
CGlobalLog::CGlobalLog()
{
minimiumLogLevel = LOGLEVEL_INFO;
}
CGlobalLog::~CGlobalLog(void)
{
if(m_instance != NULL)
delete m_instance;
}
// this method is static
CGlobalLog& CGlobalLog::getInstance()
{
if(m_instance == NULL){
m_instance = new CGlobalLog();
}
return *m_instance;
}
Where LOGLEVEL
is an enum and m_instance is CGlobalLog* CGlobalLog::m_instance
.
The trace is:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 504 at 0x009B2290: 92 bytes ----------
Call Stack:
c:\users\ferran\directo\gameprojects2008\zeleste2d\src\log\globallog.cpp (26): LogSystem_v2.exe!glog::CGlobalLog::getInstance + 0x7 bytes
c:\users\ferran\directo\gameprojects2008\zeleste2d\src\log\globallog.cpp (235): LogSystem_v2.exe!glog::CGlobalLog::exposeAPI
c:\users\ferran\directo\gameprojects200开发者_Go百科8\games_and_samples\logsystem_v2\src\main.cpp (47): LogSystem_v2.exe!main + 0xB bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (586): LogSystem_v2.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (403): LogSystem_v2.exe!mainCRTStartup
0x767D339A (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x774D9ED2 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x774D9EA5 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
Data:
00 00 00 00 CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD 28 23 9B 00 00 00 00 00 00 00 00 00 ....(#.. ........
CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD ........ ........
B0 23 9B 00 00 00 00 00 01 00 00 00 00 00 00 00 .#...... ........
CD CD CD CD 00 CD CD CD CD CD CD CD CD CD CD CD ........ ........
CD CD CD CD 00 00 00 00 0F 00 00 00 ........ ........
I couldn't find any reason for a mem leak.... could you helpme, please? Thanks in advance
First of all... How do you imagine to destructor get called? Do you call anywhere something that will destroy your object?
Secondly calling delete pointer in destructor will cause call of another destructor of same object. So you have recursive destructor call in here. As it is singleton class your call can be simply replaced with delete this;
. You should only set m_instance to NULL, so another call of getInstance will not reference to freed memory.
Solution? write static method "deleteInstance" that will check if m_instance is not null and call delete, on m_instance and set it back to null. Then you should call i.e. at end of main function CGlobalLog::deleteInstance();
. This way you will supress this memory leak
Presumably you never actually create a local CGlobalLog
because you're always using the pointer returned by GetInstance
, so the destructor never gets called. In this case it's a good thing, since you really don't want to delete your static instance until the program is finished. You'll need to make an explicit call to delete the instance member at the end of the program.
I response myself. Shame of me!! Sometimes I only need to explain the problem to find the solution. m_instance is never deleted because destructor is private, so it's a leak.
The constructor CGlobalLog::CGlobalLog()
has to initialize m_instance
to NULL. Note that if not, the results are undefined (maybe memory loss, or an invalid delete
).
There is a race condition in CGlobalLog::getInstance()
which could result in CGlobalLog
objects being leaked. Imagine two threads A and B call CGlobalLog::getInstance()
"at the same time". Thread A checks m_instance
, determines that it is not NULL
, and then prepares to construct a new CGlobalLog
object. But before the call to new
begins, the OS switches to Thread B. Thread B checks that m_instance
is not NULL
, constructs a new CGlobalLog
object, and assigns it to m_instance
. The OS might then switch to Thread A. Thread A, continuing where it left off, also constructs a new CGlobalLog
object and assigns it to m_instance
, thus leaking the instance allocated by Thread B.
Another possible cause of the problem is that the CGlobalLog
destructor deletes m_instance
if it is not NULL
. When the object being deleted is the CGlobalLog
object pointed to by m_instance
, then the object is doubly-deleted.
精彩评论