C++ 海量代码 排查内存/GDI泄漏历程

排查分两大部分:

1.代码静态分析,通过Code Review查找不合规范的代码点;

2.运行目标软件,结合内存监控工具,分析目标软件的代码,定位内存泄漏点。

目前能找到的代码静态分析软件:Coverity代码静态检查工具(Synosys公司的)、Fortify SCA(擅长JAVA,C++也能分析)、PVS-Studo、PC-lint。

内存监控工具:

Bounds check、Deleaker、CRTDBG(VS自带的,编译DEBUG版本,内存泄漏时会在Debug窗口中有打印信息)。

 

Deleaker:

                 使用简单,功能强大,除了内存泄漏还可以检查GDI泄漏,安装包自带VS插件,同时也支持其他IDE。

            下载地址:https://www.deleaker.com/

                 免费试用14天,年费$299

                 安装步骤:按照默认步骤安装。

                 使用方法:安装完后,VS中会出现一个Deleaker的菜单项,点击打开Deleaker的界面,勾选Enable后,运行调试,则Deleaker也会进入分析状态,结束调试则会完成分析结果。

       Deleaker分析代码有两种模式,一种是托管代码,一种是非托管代码,根据实际情况选择。

                 Deleaker界面如下,常用按钮已标记出来:   

                 Unmanaged Code Profiling Mode  :非托管代码模式

                 .Net Profiling Mode :托管代码模式

                 Allocation Types:可以配置要分析的缺陷类型,比如内存、GDI。

                 Take Snapshot是用来进行暂存内存快照的,和VS2017诊断工具差不多。

                 Module可以按照模块筛选分析结果,Leak Type可以按照缺陷类型筛选分析结果。

                Options项是一些高级配置,一般使用默认配置就可以了。

                最下方两个空白窗口分别是分析结果和调用栈信息,选中一条分析结果就可以精确定位到泄漏的代码行了。

                

 

Viual Leak detector:

Viual Leak detector安装后,要在VS中设置相应的头文件和库路径,在Debug模式下如果要检测相应源文件的内存泄露,则加上"#include <vld.h>"即可;

将.h文件拷贝到Visual C++的默认include目录下,将.lib文件拷贝到Visual C++的默认lib目录下,便安装完成了。(因为版本问题,如果使用windows 2000或者以前的版本,需要将dbghelp.dll拷贝到你的程序的运行目录下,或其他可以引用到的目录)。接下来需要将其加入到自己的代码中。方式很简单,只要在包含入口函数的.cpp文件中包含vld.h就可以。如果这个cpp文件包含了stdafx.h,则将包含vld.h的语句放在stdafx.h的包含语句之后,否则放在最前面。

在检测内存泄露,可以在VS的输出窗口查看输出信息。

 

CRTDbg:

      工具局限性:

                       1)对于调试非MFC程序,不能打印文件名和行号。对于一个比较大的程序,没有这些信息,解决问题将变得十分困难。

                       2)由于Debug Function实现在MS C-RuntimeLibrary中,所以它只能检测到堆内存的泄漏,而且只限于malloc,realloc或strdup等分配的内存,而那些系统资 源,比如HANDLE,GDI                                         Object,或是不通过C-Runtime Library分配的内存,比如VARIANT,BSTR的泄漏,它是无法检测到的,这是这种检测法的一个重大的局限性。

                       3)为了能记录内存块是在哪里 分配的,源代码必须相应的配合,这在调试一些老的程序非常麻烦,毕竟修改源代码不是一件省心的事,这是这种检测法的另一个局限性。

      工具使用:

                       没有工具的情况下,使用crtdbg.h中的api也是可以的,但是有之前说的两个局限性。

                       在MFC中可以看到在程序退出的时候,输出框内结尾部分输出内存泄露,并且点击可以跳转到内存泄露的代码处。

                       A) _CrtSetDbgFlag函数,这个函数用于控制debug模式下堆管理的分配行为;(函数详细信息参考:http://msdn.microsoft.com/zh-cn/library/5at7yxcs.aspx)

                           在main函数开始处添加该函数,则如果出现内存泄露Debug结束后,输出框将输出打印信息。

                                _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);  

                                //_CRTDBG_REPORT_FLAG:表示获取当前的标示位    //_CRTDBG_LEAK_CHECK_DF:表示检测内存泄露  

 

                       B) 显示内存泄露所在的文件以及行

                            能够知道有内存泄露是不够的,更需要的信息是哪里内存泄露了?

                            我们可以在每个源文件的开头定义写这样一条宏定义:

                            #define new   new(_NORMAL_BLOCK, __FILE__, __LINE__)       //根据__FILE___和__LINE__能够确定文件和行  

 

                       C) 显示内存泄露处的堆栈,(函数详细信息参考:http://technet.microsoft.com/zh-cn/library/aa246759)

                            long _CrtSetBreakAlloc( long lBreakAlloc );  //lBreakAlloc,在申请的堆区序号为lBreakAlloc处设置一个断点  

 

                            此函数在指定的申请堆区空间次序处(即lBreakAlloc)设置断点;这个函数结合"A)"中提到的{150},比如使用方法:

                            _CrtSetBreakAlloc(150); //则在第150次申请堆空间时候设置断点  .

                            这样就可以看到函数调用栈,从而帮助我们更加精确的定位程序泄露的位置.

posted @   hsqcarter  阅读(884)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示