【C++内存泄漏】使用Windbg排查C++程序内存泄漏问题

本文详细介绍了如何使用Windbg、gflags.exe和umdh.exe来定位和分析Windows程序的内存泄漏问题。通过设置gflags开启堆栈跟踪,以及在不同时间点使用umdh抓取堆内存快照,对比分析内存使用变化,从而找出内存泄漏的位置。尽管Windbg不如Linux上的Valgrind全面,但在Windows环境下仍是一个有力的排查工具。

目录

1、概述

2、使用Windbg监测内存泄漏的一般步骤

3、详解整个操作过程

3.1、gflags.exe和umdh.exe介绍

3.2、启动cmd命令行

3.3、设置pdb符号库路径

3.4、调用gflags设置启用udmh.exe的堆栈跟踪

3.5、第一次使用umdh抓取堆内存使用快照

3.6、第二次使用umdh抓取堆内存使用快照

3.7、比较两次堆内存使用快照,得出结论

 4、Windbg分析内存泄漏的不足

5、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html       最近有个客户在使用我们的Windows软件时又遇到了内存泄漏问题,软件在客户的机器环境上运行半个多小时后就会出现闪退崩溃。去年我们也遇到过类似的问题,很大概率是第三方安全软件导致的,第三方安全库注入到我们的进程中,应该是注入的库有内存泄漏,导致我们的进程出现问题。本文详细讲述一下如何使用Windbg来定位Windows程序中的内存泄漏问题。

1、概述

       Windows平台上分析内存泄漏的工具有很多,比如Rational PurifyBoundsChecker等。但这些工具已经好几年不再维护了,老的版本已不再兼容较新的Visual Studio了。即便能兼容,也是比较麻烦的,比如BoundsChecker就需要将头文件和库添加到工程中重新编译程序,大型软件中包含了多个模块,在不确定发生内存泄漏的模块的情况下,在所有模块中都添加BoundsChecker的文件重新编译一下是不现实的。

       我们需要一个工具,在不需要重新编译程序的情况下,就能直接去分析程序是否存在内存泄漏。之前一直在寻找这样的工具,一直没有找到合适的。使用过腾讯的tMemoryMonitor内存监测工具,但该工具并不好用,很多实际场景下的内存泄漏都监测不到。

       最后只能使用Windbg去检测内存泄漏。Windbg是微软提供的Windows下强大的调试工具,可以分析多种软件异常问题,在我们日常开发过程中会频繁地使用到该工具,但之前使用Windbg监测内存泄漏问题还是第一次。目前我们已经使用Windbg定位了好几起内存泄漏的问题,Windbg还是比较给力的。

2、使用Windbg监测内存泄漏的一般步骤

       在监测之前,需要安装新版本的Windbg,因为我们实际上是使用Windbg安装目录下的gflags.exeumdh.exe两个程序去完成内存监测的。

       新版本的Windbg已经合并到Windows SDK包中,要安装Windbg,则需要下载Windows SDK开发包,在安装时可以选择只安装Windbg,操作起来有点小麻烦。已经将10.0版本的Windbg安装包上传至CSDN上,直接去下载安装即可,其链接为:Windbg10 下载https://download.csdn.net/download/chenlycly/34256522

        使用gflags.exe和umdh.exe监测内存泄漏的一般步骤如下:

1)右键以管理员权限启动cmd命令行窗口,用cd命令,切换到windbg的安装目录中,比如我的安装路径是:C:\Program Files\Windows Kits\10\Debuggers\x86。
2)在cmd中输入:gflags  /i XXX.exe  +ust。(要事先将exe程序启动起来!
3)在cmd中输入:umdh.exe  -pn:XXX.exe  -f:E:\log1.txt,等待命令执行完成。
4)让软件运行一会,操作软件使之产生内存泄漏。
5)在cmd中输入:umdh.exe  -pn:XXX.exe  -f:E:\log2.txt,等待命令执行完成。
6)在cmd中输入:umdh.exe  E:\log1.txt  E:\log2.txt  -f:E:\result.txt,等待命令执行完成。
7)查看result.txt文件中的堆内存使用变化的统计,定位问题。

3、详解整个操作过程

3.1、gflags.exe和umdh.exe介绍

        gflags.exe和umdh.exe是新版本Windbg安装路径下的程序。

        gflags.exe (Global Flags) ,全局标志编辑器 ,用来启用和禁用高级调试、诊断和故障排除功能。 它通常用于打开其他工具跟踪、计数和日志的指示器。可以通过命令行执行其相关的操作,也可以在gflags的UI界面上设置:

       umdh.exe(User-Mode Dump Heap),用户转储堆程序,用来追踪并分析进程的堆内存分配。 对于每个堆内存的分配,umdh都可以追踪其分配的大小、开销的大小、指向分配的指针和分配堆栈。 如果进程具有多个活动内存堆,umdh将追踪所有堆。 此类分析可以实时展示,也可以保存在日志文件中。该工具程序是没有UI界面,是通过cmd命令行执行相关操作的。

3.2、启动cmd命令行

       一般我们需要右键以管理员权限运行cmd命令行窗口,特别是在Win10系统中。然后用cd命令,切换到windbg的安装目录中,比如我的安装路径是:C:\Program Files\Windows Kits\10\Debuggers\x86,以方便下面在命令行中直接启动该路径下的gflags.exe和umdh.exe两个程序。

3.3、设置pdb符号库路径

       umdh最终会分析出使用堆内存的函数调用堆栈,为了方便查看到函数调用堆栈中的具体函数,可以设置pdb符号库文件路径。我们可以在命令行中设置如下的环境变量:

set _NT_SYMBOL_PATH="D:\MySymbols;srv*C:\WINDOWS\Symbols*http://msdl.microsoft.com/download/symbols"

环境变量的名称为_NT_SYMBOL_PATH,其值是包含pdb的路径。路径包含两部分,前半部分的D:\MySymbols是我们软件模块的符号库文件,后半部分则是微软系统库在线下载的符号库路径。

       如果不想设置微软系统库在线pdb路径,可以只设置软件自己模块的pdb文件。除了在命令行中添加环境变量,也可以在系统中添加环境变量。以win10系统为例,在系统搜索栏中搜索环境变量,找到编辑环境变量的入口,依次操作即可:

3.4、调用gflags设置启用udmh.exe的堆栈跟踪

        继续在cmd命令行中输入:

gflags /i XXX.exe +ust

其中/i用来指定目标进程的名称,参数ust的含义是:Create user mode stack trace database。此命令用来给目标进程创建用户模式堆栈跟踪数据库,用于追踪堆内存的使用情况


         在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:【C++软件异常与异常排查从入门到精通系列教程】该精品技术专栏的订阅量已达到50000多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,已经更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法详细讲述了C++软件的调试方法与手段详细介绍分析C++软件问题的常用分析工具,以图文并茂的方式给出具体的项目问题实战分析实例(详细讲述分析排查过程,很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:【C/C++实战进阶】(该专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达30000多个,专栏文章已经更新到500多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法C++11及以上新特性(开源代码中可能会用到很多新特性(比如WebRTC开源库),日常编码中也会用到部分新特性,面试时也会频繁地涉及到,学习新特性很有必要)、常用C++开源库的介绍与使用(比如SQLite、libcurl、libwebsockets、libevent、jsoncpp/RapidJson、Redis、RabbitMQ、MongoDB、MQTT、ZooKeeper、OpenCV、FFmpeg、SDL、GStreamer、Live555、ReactOS等)、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(引发C++软件异常的常见原因分析与总结、排查C++软件异常的手段与方法、分析C++软件异常的基础知识、使用常用软件分析工具分析C++软件问题、多个项目实战问题分析案例分享等)、设计模式(单例模式、工厂模式、观察者模式、状态模式等)、网络基础知识与网络问题分析进阶内容(实战问题分析实例分享)等。本专栏的内容都是建立在项目实践的基础上,来源于项目实战,服务于项目实战,很有实战参考价值!

专栏3:【分析C++软件问题的实用软件与高效工具实战案例集锦】

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro以及内存泄漏检测工具等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏4:【VC++常用功能代码封装】

VC++常用功能开发汇总(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5:【C/C++软件开发从入门到实战】

C++ 软件开发从入门到精通(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


3.5、第一次使用umdh抓取堆内存使用快照

        继续在cmd命令行中输入:

umdh.exe -pn:XXX.exe -f:E:\log1.txt

其中-pn参数用来指定目标进程的进程名,-f参数用来指定存放抓取来的堆内存使用快照数据信息。此命令运行后,将第一次抓取的堆内存使用快照数据保存到E:\log1.txt中

       输入该命令后,让程序运行一会,尽可能运行的时间长一会,保证在这段时间内产生足够多的内存泄漏,这样windbg的监测结果更准确一些。

3.6、第二次使用umdh抓取堆内存使用快照

        继续在cmd中输入如下的命令:

umdh.exe -pn:XXX.exe -f:E:\log2.txt

命令说明同上。此命令运行后,将第二次抓取的堆内存使用快照数据保存到E:\log2.txt中

3.7、比较两次堆内存使用快照,得出结论

        最后在cmd中输入:

umdh.exe E:\log1.txt E:\log2.txt -f:E:\result.txt

比较log1.txt 和log2.txt两文件中的堆内存使用变化量,得出统计数据,将统计结果保存到E:\result.txt文件中。打开E:\result.txt,即可查看到堆内存的变化情况,按堆内存申请数量从高到底排列,每一项统计结果都有详细的函数调用堆栈,一般我们只需要分析使用量较高的几项即可。一般第一项就是发生内存泄漏的堆栈,比如:

 4、Windbg分析内存泄漏的不足

       Windbg只能监测两个时间点的申请堆内存的变化量,并没有去统计释放的堆内存,这一点和Linux上排查内存泄漏的神器Valgrind要差一些。所以Windbg统计出来的结果中,排在第一位的项可能并不是内存泄漏的项,需要我们去结合代码将其他几项过滤掉,最终确定发生内存泄漏的那一项。 

5、最后

       有时遇到的内存泄漏问题,可能很难排查,用一个工具很难定位,这时就需要尝试多种工具和方法。

  • 如果问题发生在Windows平台上,则可以尝试使用Windbg、Visual Leak Detector(VLD)、VMMap、DebugDiag等工具去分析。
  • 如果问题发生在Linux平台上,则可以尝试使用Valgrind、AddressSanitizer等内存专用检测工具去排查。

       一个工具难以定位时,可以尝试使用其他工具,直到分析出问题为止。可以到我的内存泄漏排查专栏中,查看上述工具的使用方法:

C++内存泄漏排查https://blog.csdn.net/chenlycly/category_12370029.html%20%20%E2%80%8B

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dvlinker

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

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

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

打赏作者

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

抵扣说明:

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

余额充值