acloudhuang的专栏

C++方面的老家伙了

内存泄露的排查

内存泄露的排查

黄国强 2010-5-24

1 内存泄露的现象和危害
      在C++中,当我们用 new 分配了一段内存,而在用完了以后忘了用 delete 释放,这样内存泄露就产生了。
      内存泄露对于长期运行的程序 是致命的,它会导致系统可用内存越来越少,最终导致将程序崩溃。下面用具体的例子来说明内存泄露的产生,以及解决的方法。

2 例子工程的建立
      使用VC7.1(也就是VS2003),创建过程的设置如下:
      step1:新建项目,项目选 项是“Visual C++项目/win32/win32控制台项目”
      step2:在随后弹出的“应用程序设置”的“应用程序类型”中“选择控制 台应用程序”,并在“添加支持”中选择“MFC”。

3 内存泄露的代码示例1

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // 初始化 MFC 并在失败时显示错误
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: 更改错误代码以符合您的需要
        _tprintf(_T("致命错误: MFC 初始化失败/n"));
        nRetCode = 1;
    }
    else
    {
        // TODO: 在此处为应用程序的行为编写代码。
    }
    int * p = new int;        // 分配了大小为一个int的内存
    int * p2 = new int[8];     // 分配了一个int数组的内存
    return nRetCode;
}

选择Debug,运行这个程序。

在VC输出栏就会出现下面的提示,说明有内 存泄露存在。(当然这个例子是否有害,在此不讨论)
Detected memory leaks!
Dumping objects ->
d:/temp/meleak/meleak/meleak.cpp(34) : {120} normal block at 0x00346300, 32 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
d:/temp/meleak/meleak/meleak.cpp(33) : {119} normal block at 0x003462C0, 4 bytes long.
 Data: <    > CD CD CD CD

我们在VC输出栏中双击
“d:/temp/meleak/meleak/meleak.cpp(34) : {120} normal block at 0x00346300, 32 bytes long.”,VC就会自动定位到源码发生内存泄露的位置。(我曾经遇到过好几次,有人居然不知道这个功能。所以特别写下来,希望不是废话)

解决的方法就是分别写上如下两行代码即可。
    delete p;         // 释放一般指针
    delete[] p2;     // 释放数组
但是以上方法不好,下面推荐的是另外一种方法。代码如下:
std::auto_ptr<int> p3(new int);
std::vector<int> p4(8);
p =  p3.get();     // 这时候的p无需释放
p2 = &p4[0];     // 这时候的p2也无需释放

4 内存泄露的代码示例2
下 面是一个比较隐蔽的例子

class CBase
{
public:
    CBase(void){}
    ~CBase(void){}
};

class CDerive : public CBase
{
public:
    CDerive(const CString& strVal):m_strVal(strVal){}
    ~CDerive(void){}

private:
    CString m_strVal;
};

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // 初始化 MFC 并在失败时显示错误
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: 更改错误代码以符合您的需要
        _tprintf(_T("致命错误: MFC 初始化失败/n"));
        nRetCode = 1;
    }
    else
    {
        // TODO: 在此处为应用程序的行为编写代码。
    }
    std::auto_ptr<CBase> pBase(new CDerive("文本"));
    return nRetCode;
}

选择Debug,运行这个程序。
在VC输出栏就会出现下面的提 示,说明有内存泄露存在。
Detected memory leaks!
Dumping objects ->
{124} normal block at 0x00346390, 21 bytes long.
 Data: <  2|            > D8 BC 32 7C 04 00 00 00 04 00 00 00 01 00 00 00
Object dump complete.

上面的这段提示,并没有给出是哪行代码出了问题,这时我们可以用到下面的方法。
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    _CrtSetBreakAlloc(124); // 加入此行,124就是VC输出栏的{}中的数字
    ...
}

选择 Debug 运行这个程序。一旦分配到124这个内存,VC就会停下来,这样,我们就可以从调用堆栈中查出是哪一行导致内存泄露。
这个bug的原因是在 ~CBase(void){} 少了个 virtual。下面的是正确的写法。

class CBase
{
public:
    CBase(void){}
    virtual ~CBase(void){}
};   

阅读更多
个人分类: C/C++
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭