VC++内存泄漏检测方法(5):使用强大的Windbg工具,重点是Symbols Path设置

简介: VC++内存泄漏检测方法(5):使用强大的Windbg工具,重点是Symbols Path设置

前面4篇文章提到的方法,已经可以解决我们的大部分内存泄露问题了,但是这些方法是有前提的,那就是一定要有源代码,而且还只能是Debug版本调试模式下。实际上很多时候,我们的程序会用到第三方没有源代码的模块,有些情况下模块有内存泄露,但是没有证据,又或者VC++ MFC退出提示有内存泄漏,但是信息不足,不好定位是哪个文件哪个函数出问题,我们该怎么办? 这时我们就要依靠无所不能的WinDbg了。


不了解windbg的读者,请见我的另一篇博客《Windows平台的Windbg/x64dbg/OllyDbg调试器》


Windows SDK v10

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe

C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\windbg.exe

gflags.exe和windbg.exe在同一个安装路径

1、先运行Windbg安装目录下的gflags.exe,Image File,Image填exe名字,不要全路径,选上Create user mode stack trace database;


image.png


2、准备好Windows系统的环境变量,添加环境变量_NT_SYMBOL_PATH和_NT_ALT_SYMBOL_PATH,而_NT_SYMBOL_PROXY是可选项,非必需。


_NT_SYMBOL_PATH=C:\Symbols;srv*C:\Symbols*http://msdl.microsoft.com/download/symbols

_NT_ALT_SYMBOL_PATH=cache*C:\Symbols

_NT_SYMBOL_PROXY=127.0.0.1:8100

(1)这句话的意思是:指定用于符号解析的符号路径为本地路径C:\Symbols,如果找不到就去http://msdl.microsoft.com/download/symbols下载,存放路径是C:\Symbols。所以第1次断点调试时,可能需要下载等很久,第2次以后就不会了。


(2)一定要用C:\Symbols这个目录,不要用自定义的目录。否则会提示错误,如下:

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for ntdll.dll -


image.png


(3)考虑到.pdb符号文件较大,为了给系统盘瘦身,不想把符号文件放在C盘,那就可以采用mklink加入文件链接的方法。用管理员权限打开CMD(windows开始菜单-所有程序-附件-命令提示符-右键,以管理员身份运行),输入命令:


mklink /D C:\Symbols E:\software\Qt\symbolcache

这样会在C盘建立链接C:\Symbols,它实际指向的是E盘自定义路径。


(4)环境变量_NT_SYMBOL_PATH的设置不仅仅适用于WinDbg。实际上,所有调试器(至少Microsoft的VS调试器)都将使用此设置。VS2017的调试选项如图:


image.png


image.png


之后我用VS调试器,因为第1次调试时已经下载了符号文件到本地,第2次及以后调试时,记得要去掉"Mincrosoft符号服务器"的勾选,然后点击F5进入调试。但是我发现了一个问题,即状态栏每次都提示从服务器下载并加载符合文件,文件很多还很慢。按理说,第1次调试时,符号文件pdb不是已经下载到本地磁盘了吗?怎么又要下载?这是一个潜在的坑:


原来VS调试器运行过程中,它任何时候都会从windows服务器加载;windows符号本地有了还仍然去svr查找;微软服务器符号加载如此之慢,竟然有时快有时慢!详情见《微软符号服务器_NT_SYMBOL_PATH给VS调试带来的隐藏坑》


解决方法有以下两种(推荐方法2):


(1)到环境变量里,删除或者重命名_NT_SYMBOL_PATH变量;


(2)到环境变量里,设置_NT_SYMBOL_PROXY,指向一个无效的代理服务器IP和Port;


重启VS,OK!!


3、运行Windbg.exe,(注意,32位程序请使用32位windbg调试,64位程序用64位windbg调试。)


(1)菜单File-Symbol File Path,或者Ctrl+S,弹框,请输入用户程序的.pdb符号文件路径(非必须,如果没有pdb文件则略过该步骤):


C:\Users\firecat\source\repos\SmartDispenser\Debug

加上之前已配置的环境变量_NT_SYMBOL_PATH,最终的符号文件路径会成为:


C:\Users\firecat\source\repos\SmartDispenser\Debug;C:\Symbols;srv*C:\Symbols*http://msdl.microsoft.com/download/symbols

windbg命令行的符号命令介绍:


.sympath #查看符号目录


.reload #重新加载符号目录


!sym noisy #利用 !sym noisy 命令可以清楚发现 Symbols 安装到底在哪里出了问题


!heap #查看堆栈


(2)菜单File-Open Executable-打开需要调试的exe文件


(3)菜单Debug-Go,一步一步得运行


(4)exe在手动关闭退出时windbg会显示内存泄漏:


Detected memory leaks!

Dumping objects ->

{194} normal block at 0x04091C20, 8 bytes long.

Data: <Ll y    > 4C 6C 86 79 01 CD CD CD

Object dump complete.


可以发现地址0x04091C20就是内存泄漏的地址,泄漏8个字节,但是信息仍不足,不好定位究竟是哪个文件哪个函数出了问题,我们该怎么办?解决办法如下:


通过!heap命令对该地址进行分析,可以发现具体的调用堆栈:


!heap -p -a 0x04091C20


image.png

image.png


通过这句提示,可以发现问题所在:


TKernel!TCollection_AsciiString::TCollection_AsciiString+0x00000036


相关文章
|
13天前
|
开发工具 Swift iOS开发
【Swift开发专栏】Swift中的内存泄漏检测与修复
【4月更文挑战第30天】本文探讨了Swift中的内存泄漏问题,尽管有ARC机制,但仍需关注内存管理。文章分为三部分:内存管理基础知识、检测方法和修复技巧。了解ARC原理和循环引用陷阱是防止内存泄漏的关键。检测方法包括使用Xcode内存调试器、LeakSanitizer和性能分析工具。修复技巧涉及打破循环引用、使用弱/无主引用及手动管理内存。理解这些对优化应用性能和稳定性至关重要。
|
1月前
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
40 9
|
1月前
|
编译器 开发工具 C++
Dev-C++详细安装教程及中文设置(附带安装包链接)
Dev-C++详细安装教程及中文设置(附带安装包链接)
78 0
|
5天前
|
Arthas Prometheus 监控
JVM工作原理与实战(二十九):监控内存泄漏的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了解决内存溢出的步骤、Top命令、VisualVM、Arthas、Prometheus + Grafana等内容。
12 0
|
6天前
|
安全 Linux Python
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
|
6天前
|
数据安全/隐私保护 Python Windows
Volatility2.6内存取证工具安装及入门-2
Volatility2.6内存取证工具安装及入门
Volatility2.6内存取证工具安装及入门-2
|
6天前
|
安全 Python Linux
Volatility2.6内存取证工具安装及入门-1
Volatility2.6内存取证工具安装及入门
Volatility2.6内存取证工具安装及入门-1
|
8天前
|
缓存 Linux
linux性能分析之内存分析(free,vmstat,top,ps,pmap等工具使用介绍)
这些工具可以帮助你监视系统的内存使用情况、识别内存泄漏、找到高内存消耗的进程等。根据具体的问题和需求,你可以选择使用其中一个或多个工具来进行内存性能分析。注意,内存分析通常需要综合考虑多个指标和工具的输出,以便更好地理解系统的行为并采取相应的优化措施。
27 6
|
12天前
|
Dart 前端开发 Java
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
【4月更文挑战第30天】本文探讨了Flutter应用中的内存泄漏检测与解决方法。内存泄漏影响性能和用户体验,常见原因包括全局变量、不恰当的闭包使用等。开发者可借助`observatory`工具或`dart_inspector`插件监测内存使用。解决内存泄漏的策略包括避免长期持有的全局变量、正确管理闭包、及时清理资源、妥善处理Stream和RxDart订阅、正确 disposal 动画和控制器,以及管理原生插件资源。通过这些方法,开发者能有效防止内存泄漏,优化应用性能。
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
|
13天前
|
数据可视化 Java 测试技术
【Go语言专栏】Go语言中的内存泄漏检测与修复
【4月更文挑战第30天】Go语言内存泄漏详解:概念、原因、检测与修复。内存泄漏由忘记释放内存、循环引用等引起,Go通过垃圾回收机制管理内存,但仍有泄漏风险。检测方法包括pprof、可视化工具、代码审查和单元测试。修复策略涉及优化代码、使用defer、减少全局变量、弱引用及及时释放资源。实践案例分析有助于理解和解决问题。了解内存管理,防止泄漏,提升Go应用性能和稳定性。