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次申请堆空间时候设置断点 .
这样就可以看到函数调用栈,从而帮助我们更加精确的定位程序泄露的位置.
C++ 海量代码 排查内存/GDI泄漏历程的更多相关文章
- GDI泄漏排查经验零散总结
1.GDI对象以及释放方法: GDI对象 产生方法 销毁方法 位图(HBITMAP) CreateBitmap,CreateBitmapIndirect, CreateCompatibleBitmap ...
- APP排查内存泄漏最简单和直观的方法
内存泄漏无疑会严重影响用户体验,一些本应该废弃的资源和对象无法被释放,导致手机内存的浪费,app使用的卡顿,那么如何排查内存泄漏呢? 当然,首先我们有google的官方文档可以参考,大部分博客 ...
- uilib库gdi句柄泄漏bug修复,duilib防止gdi泄漏的小提醒
转载请说明原出处,谢谢~~ 今天下午群友的网友让我帮忙看一下的duilib程序的问题,程序中包含了List控件,会定时清除所有子项目然后重新添加.但是程序运行一段时间后会自己崩溃!我编译了源码运行后在 ...
- GDI 泄漏检测方法
方法一 1.打开电脑的[任务管理器],选择[进程]页,点击菜单项的[查看]项,选择[选择列]: 2.勾选[GDI对象(J)]即可. 3.此时,用户就可以在进程中看到每个进程对应的GDI对象,每个进程的 ...
- 解密native代码的内存使用
前言 无论是从资源使用的角度,还是从发现内存泄漏问题的角度来看,在性能测试或者系统的稳定性测试中,内存的使用情况是一个很重要的监控点.为保证项目的质量前移,输入法内核测试小组的同学分配到了一个新的任务 ...
- Pythontutor:可视化代码在内存的执行过程
http://www.pythontutor.com/visualize.html今天去问开发一个Python浅拷贝的问题,开发给了一个神器,可以可视化代码在内存的执行过程,一看即懂,太NB了!~真是 ...
- c++ 汇编代码看内存分配
汇编代码看内存分配 (1). 程序运行时分为存储区域分为 存储区域 存储内容 extra 代码区 存放代码指令,包括除字符串常量的字面值 静态存储区 存放静态变量和全局变量 执行main之前就分配好了 ...
- [android网络有效性检测] NetworkMonitor代码造成内存泄漏
造成内存泄漏的log如下: E StrictMode: A resource was acquired at attached stack trace but never released. See ...
- 记一次使用windbg排查内存泄漏的过程
一.背景 近期有一个项目在运行当中出现一些问题,程序顺利启动,但是观察一阵子后发现内存使用总量在很缓慢地升高, 虽然偶尔还会往下降一些,但是总体还是不断上升:内存运行6个小时候从33M上升到80M: ...
随机推荐
- Android EventBus踩坑,Activity接收不了粘性事件。
注解问题 EventBus 的 粘性事件,可以让 成功注册后的 Activity.Fragment 后再接收处理 这一事件. 但是今晚写代码时,突然发现粘性事件,发送不成功了.??? 具体情况是:我在 ...
- vue element select多选回显
我们经常在使用 Element组件里面的 select多选 场景:添加账号的时候需要选择可见分公司(分公司为多选),添加成功之后可以编辑,需要回显添加时所提交的分公司 代码如下: 多选框: data( ...
- ELK+kafka日志收集分析系统
环境: 服务器IP 软件 版本 192.168.0.156 zookeeper+kafka zk:3.4.14 kafka:2.11-2.2.0 192.168.0.42 zookeeper+kaf ...
- C. K-Complete Word(小小的并查集啦~)
永久打开的传送门 \(\color{Pink}{-------------分割-------------}\) \(n最大有2e5,那么暴力一定不行,找规律\) \(我们发现第i位的字符一定和第i+k ...
- ubuntu18.04下mysql安装时没有出现密码提示
前言: 一:配置 ubuntu 18.04 mysql 5.7.30 二:问题 ubuntu18.04下mysql安装时没有出现密码提示,安装后自己有一个默认的用户名以及密码 解决方案: 1. 在终端 ...
- 一分钟明白MySQL聚簇索引和非聚簇索引
MySQL的InnoDB索引数据结构是B+树,主键索引叶子节点的值存储的就是MySQL的数据行,普通索引的叶子节点的值存储的是主键值,这是了解聚簇索引和非聚簇索引的前提 什么是聚簇索引? 很简单记住一 ...
- Kafka 的一些知识点整理【1】
First: Kafka 是什么? Kafka 是一个发布订阅系统 最初是是LinkedIn 开发 最后交给Apache 开源组织 github地址:https://github.com/apache ...
- 【Spark】Spark-shell案例——standAlone模式下读取HDFS上存放的文件
目录 可以先用local模式读取一下 步骤 一.先将做测试的数据上传到HDFS 二.开发scala代码 standAlone模式查看HDFS上的文件 步骤 一.退出local模式,重新进入Spark- ...
- 【Hadoop离线基础总结】MapReduce参数优化
MapReduce参数优化 资源相关参数 这些参数都需要在mapred-site.xml中配置 mapreduce.map.memory.mb 一个 MapTask 可使用的资源上限(单位:MB),默 ...
- springMVC的自定义annotation(@Retention@Target)详解
自定义注解: 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节.在定义注解时,不能继承其他的注解或接口.@ ...