排查分两大部分:

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泄漏历程的更多相关文章

  1. GDI泄漏排查经验零散总结

    1.GDI对象以及释放方法: GDI对象 产生方法 销毁方法 位图(HBITMAP) CreateBitmap,CreateBitmapIndirect, CreateCompatibleBitmap ...

  2. APP排查内存泄漏最简单和直观的方法

        内存泄漏无疑会严重影响用户体验,一些本应该废弃的资源和对象无法被释放,导致手机内存的浪费,app使用的卡顿,那么如何排查内存泄漏呢? 当然,首先我们有google的官方文档可以参考,大部分博客 ...

  3. uilib库gdi句柄泄漏bug修复,duilib防止gdi泄漏的小提醒

    转载请说明原出处,谢谢~~ 今天下午群友的网友让我帮忙看一下的duilib程序的问题,程序中包含了List控件,会定时清除所有子项目然后重新添加.但是程序运行一段时间后会自己崩溃!我编译了源码运行后在 ...

  4. GDI 泄漏检测方法

    方法一 1.打开电脑的[任务管理器],选择[进程]页,点击菜单项的[查看]项,选择[选择列]: 2.勾选[GDI对象(J)]即可. 3.此时,用户就可以在进程中看到每个进程对应的GDI对象,每个进程的 ...

  5. 解密native代码的内存使用

    前言 无论是从资源使用的角度,还是从发现内存泄漏问题的角度来看,在性能测试或者系统的稳定性测试中,内存的使用情况是一个很重要的监控点.为保证项目的质量前移,输入法内核测试小组的同学分配到了一个新的任务 ...

  6. Pythontutor:可视化代码在内存的执行过程

    http://www.pythontutor.com/visualize.html今天去问开发一个Python浅拷贝的问题,开发给了一个神器,可以可视化代码在内存的执行过程,一看即懂,太NB了!~真是 ...

  7. c++ 汇编代码看内存分配

    汇编代码看内存分配 (1). 程序运行时分为存储区域分为 存储区域 存储内容 extra 代码区 存放代码指令,包括除字符串常量的字面值 静态存储区 存放静态变量和全局变量 执行main之前就分配好了 ...

  8. [android网络有效性检测] NetworkMonitor代码造成内存泄漏

    造成内存泄漏的log如下: E StrictMode: A resource was acquired at attached stack trace but never released. See ...

  9. 记一次使用windbg排查内存泄漏的过程

    一.背景 近期有一个项目在运行当中出现一些问题,程序顺利启动,但是观察一阵子后发现内存使用总量在很缓慢地升高, 虽然偶尔还会往下降一些,但是总体还是不断上升:内存运行6个小时候从33M上升到80M: ...

随机推荐

  1. 5) ModelSerializer(重点) 基表 测试脚本 多表关系建外键 正反查 级联 插拔式连表 序列化反序列化整合 增删查 封装response

    一.前戏要做好 配置:settings.py #注册drf INSTALLED_APPS = [ # ... 'api.apps.ApiConfig', 'rest_framework', ] ​ # ...

  2. MySQL导出数据到文件中的方法

    MySQL导出数据到文件中的方法 1.导出数据到txt文件中实例:把数据表studscoreinfo中所有数据导出到指定的位置方法:select * from 表名 into outfile 指定导出 ...

  3. Java笔记(day14-17)

    集合类的由来: 对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定. 就使用集合容器进行存储. 集合特点: 1,用于存储对象的容器. 2,集合的长度是可变的. 3,集合中不可以存储基本数据类 ...

  4. SpringData Redis的简单使用

    SpringDate Redis是在Jedis框架的基础之上对Redis进行了高度封装,通过简单的属性配置就可以通过调用方法完成对Redis数据库的操作,而且SpringData Redis使用了连接 ...

  5. LeetCode--LinkedList--203. Remove Linked List Elements(Easy)

    203. Remove Linked List Elements(Easy) 题目地址https://leetcode.com/problems/remove-linked-list-elements ...

  6. 【FPGA篇章二】FPGA开发流程:详述每一环节的物理含义和实现目标

    欢迎大家关注我的微信公众账号,支持程序媛写出更多优秀的文章 FPGA的开发流程是遵循着ASIC的开发流程发展的,发展到目前为止,FPGA的开发流程总体按照下图进行,有些步骤可能由于其在当前项目中的条件 ...

  7. ActiveMQ 事务、集群、持久订阅者、ActiveMQ监控

    JMS介绍 JMS是什么? JMS的全称Java Message Service,既Java消息服务. JMS是SUN提供的旨在统一各种MOM(Message-Oriented Middleware) ...

  8. Day_10【常用API】扩展案例2_获取输入日期是哪一年的哪一天的星期几

    分析以下需求,并用代码实现 1)已知日期字符串:"2015-10-20",将改日期字符串转换为日期对象 2)将(1)中的日期对象转换为日历类的对象 3)根据日历对象获取改日期是星期 ...

  9. FOC中电流环调试的宝贵经验总结(有理有据+全盘拖出)

    你是否经历过一个人独自摸索前进磕磕碰碰最终体无完肤,然后将胜利的旗帜插到山顶的时刻,如果有,本文也许能帮你在调试FOC电流环的时候给你带来一些帮助和思路. 如果本文帮到了您,请帮忙点个赞

  10. [hdu1085]生成函数

    题意:给a个1.b个2.c个5,求不能构成最小的数 思路: 先求1能构成的所有数,2能构成的所有数,5能构成的所有数,它们的方法数显然都是1,现在考虑把3者结合在一起,由于结果为和的形式,而又是循环加 ...