我正在使用VLD(Visual Leak Detector),它会检测到一些内存泄漏。我试图理解为什么这是VLD的内存泄漏。这可能是假阳性?
代码非常简单:
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;
}
其中LOGLEVEL
是枚举,m_instance是CGlobalLog* CGlobalLog::m_instance
。
跟踪是:
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\gameprojects2008\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 ........ ........
我找不到内存泄漏的任何理由......你能帮忙吗? 提前致谢
答案 0 :(得分:2)
大概你从未真正创建本地CGlobalLog
因为你总是使用GetInstance
返回的指针,所以析构函数永远不会被调用。在这种情况下,这是一件好事,因为在程序完成之前,您真的不想删除静态实例。您需要显式调用以删除程序末尾的实例成员。
答案 1 :(得分:2)
首先......你怎么想象析构函数被调用?你是否在任何会破坏你的物体的地方打电话?
其次,在析构函数中调用delete指针将导致调用同一对象的另一个析构函数。所以你在这里有递归析构函数调用。由于它是单身类,您的电话可以简单地替换为delete this;
。您应该只将m_instance设置为NULL,因此另一个getInstance调用将不会引用释放的内存。
解决方案?编写静态方法“deleteInstance”,它将检查m_instance是否为null并在m_instance上调用delete,并将其设置为null。然后你应该在主函数CGlobalLog::deleteInstance();
结束时调用。这样你就会压制这个内存泄漏
答案 2 :(得分:1)
我回应自己。惭愧我!!有时我只需要解释问题就可以找到解决方案。永远不会删除m_instance,因为析构函数是私有的,所以它是一个泄漏。
答案 3 :(得分:1)
构造函数CGlobalLog::CGlobalLog()
必须将m_instance
初始化为NULL。请注意,如果没有,结果是未定义的(可能是内存丢失,或者是无效的delete
)。
答案 4 :(得分:0)
CGlobalLog::getInstance()
中存在竞争条件,可能导致CGlobalLog
个对象泄露。想象一下,两个线程A和B同时调用CGlobalLog::getInstance()
“。线程A检查m_instance
,确定它不是NULL
,然后准备构造一个新的CGlobalLog
对象。但在调用new
之前,操作系统切换到线程B.线程B检查m_instance
不是NULL
,构造一个新的CGlobalLog
对象,并将其分配给m_instance
。然后,操作系统可能会切换到线程A.线程A继续停止,它还构造一个新的CGlobalLog
对象并将其分配给m_instance
,从而泄漏线程B分配的实例。
问题的另一个可能原因是,如果CGlobalLog
析构函数不是m_instance
,则NULL
析构函数会删除CGlobalLog
。当被删除的对象 m_instance
指向的{{1}}对象时,该对象被双重删除。