试图了解内存泄露的原因

Trying to understand a mem leak

本文关键字:了解 内存      更新时间:2023-10-16

我正在使用VLD(视觉泄漏检测器),它检测到一些内存泄漏。我想知道为什么这是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为enum, m_instance为CGlobalLog* CGlobalLog::m_instance。trace是:

WARNING: Visual Leak Detector detected memory leaks!
---------- Block 504 at 0x009B2290: 92 bytes ----------
  Call Stack:
    c:usersferrandirectogameprojects2008zeleste2dsrcloggloballog.cpp (26): LogSystem_v2.exe!glog::CGlobalLog::getInstance + 0x7 bytes
    c:usersferrandirectogameprojects2008zeleste2dsrcloggloballog.cpp (235): LogSystem_v2.exe!glog::CGlobalLog::exposeAPI
    c:usersferrandirectogameprojects2008games_and_sampleslogsystem_v2srcmain.cpp (47): LogSystem_v2.exe!main + 0xB bytes
    f:ddvctoolscrt_bldself_x86crtsrccrtexe.c (586): LogSystem_v2.exe!__tmainCRTStartup + 0x19 bytes
    f:ddvctoolscrt_bldself_x86crtsrccrtexe.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                    ........ ........

我找不到内存泄漏的任何原因....你能帮我一下吗?提前感谢

首先…你想象如何调用析构函数?你在任何地方调用会破坏你的对象的东西吗?

其次,在析构函数中调用delete指针将导致调用同一对象的另一个析构函数。这里有递归析构函数调用。由于它是单例类,您的调用可以简单地替换为delete this;。你应该只将m_instance设置为NULL,这样getInstance的另一次调用将不会引用释放的内存。

解决方案吗?编写静态方法"deleteInstance",检查m_instance是否不为空,并在m_instance上调用delete,并将其设置为空。然后你应该在主函数CGlobalLog::deleteInstance();的末尾调用i.e.。这样可以抑制内存泄漏

您可能从未真正创建过一个本地CGlobalLog,因为您总是使用GetInstance返回的指针,因此析构函数从未被调用。在本例中,这是一件好事,因为在程序完成之前,您确实不希望删除静态实例。您需要在程序末尾进行显式调用以删除实例成员。

我自己回应。我真丢脸!!有时候我只需要解释问题就能找到解决方法。M_instance永远不会被删除,因为析构函数是私有的,所以它是一个泄漏。

构造函数CGlobalLog::CGlobalLog()必须将m_instance初始化为NULL。注意,如果不是,结果是未定义的(可能是内存丢失,或者无效的delete)。

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。当被删除的对象m_instance所指向的CGlobalLog对象时,则该对象被双重删除。