内存泄露之一: First-chance exception at 0x7502845D in NMEPanel.exe:

一项目,Debug调试完成,编译都OK,没问题,运行,每次运行2小时左右,就崩溃,出现标题上的错误信息,有未处理的报警,第一时间的反应是内存泄露,因为调试编译没问题,而且能运行2小时,说明至少结构没啥大问题,开始查泄露,一步步来,将线程一个个关掉,用_CrtDumpMemoryLeaks()函数一个个函数检查,将几处有可能泄露的GDI对象(如CImage,CFont)全部使用全局变量,由于这些对象之前在函数里面已经释放了,所以即使用全局变量的形式,也仍然没有阻止泄露的产生,仍然是每分钟4K字节增加,在任务管理器中可以清楚地看到,调试了两天,所有该检查的地方差不多都查了个遍,无果,几近崩溃,甚至想放弃,没办法,生活还得继续,沮丧之后,还得查,看了无数的博客,由于本人不是计算机毕业的,之前学的是自动化,搞搞软硬件控制还行,但涉及到计算机软件内核的技术还是软肋,那怎么办,恶补呗,还是从线程查,所有线程全部关闭之后,发现里面还有四个线程,在VS2017线程里可以看到,

这里只有三个,其中一个mssocket线程已经被关闭了,按说程序已经没有我要求运行的任何代码了,就相当于个打开的对话框,静静地放在那里,没做任何事,这下应该不会有泄露了吧,但偏偏事与愿违,每分钟4K的泄露,一点不少,既然还有泄露,那继续,里面三个线程,其中ntdll.dll是微软内核线程,专门负责ring0底层动作,应该与泄露无关,即使有也不怀疑它,剩下两个,一个是主线程,一个是GDI,主线程已经不运行了,那剩下就是GDI,看还有哪个GDI在运行,在主程序里查了一晚上没查出,所有的GDI对象都被全局化了,不可能不断地需要新的内存,那到底是哪里出了问题呢,一个个模块查,最后发现在一个子窗口类中有这么一段:


HBRUSH CNotice::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (IDC_STNOTICE == pWnd->GetDlgCtrlID())//判断发出消息的空间是否是通知消息静态文本框
    {
        pDC->SetTextColor(RGB(255, 0, 0));//设置文本颜色为红色
        pDC->SetBkMode(OPAQUE);//设置文本背景模式为透明
        pDC->SetBkColor(RGB(127, 127, 255));//设置文本背景为蓝色
        HBRUSH m_brush = CreateSolidBrush(RGB(127, 127, 255));   <======== 问题的根源
        return m_brush;
    }
    // TODO:  在此更改 DC 的任何特性

    // TODO:  如果默认的不是所需画笔,则返回另一个画笔
    return hbr;
}

因为这段话是抄来的,也不知道是哪个网友还是哪个菜鸟写的,反正无处查正了,总之肯定不是自己写的,虽然主线程里没有任何动作,但这个窗口还是在显示,每次显示都有一个静态控件要重绘,而所有人都知道,CreateSolidBrush产生的画刷是必须释放的,不然,每次在OnCtrColor消息产生时,都会创建一个刷子,这个刷子是要消耗内存的,难怪2小时之后, 就自动崩溃了.原因找到.立即做一个全局的刷子,问题消失.

问题总结:1.之前总担心GDI对象全局化能不能行,会不会产生泄露或者其它意想不到的问题,现在可以肯定地回答 :不会,如果要频繁绘图,(特别是在OnPaint中绘图),最好用全局的GDI对象,我这里有五幅图片,用了五个CImage,每次绘图时直接调用就行了,不必每次load,还有CFont,HBRUSH,CPen,等,都可以全局化,少了每次使用的创建和销毁,运行效率更高,内存消耗也小了很多.

2.查内存泄露,光靠_CrtDumpMemoryLeaks()函数是不行的,必须看任务管理器,如果运行几分钟都没有看到内存增长,那恭喜你,大问题不会有了,但交互时操作的地方还要小心,不过那个可以控制在较小的范围.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zzzzzmonkey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值