c++内存泄漏问题定位
内存泄漏指的是直接操作内存分配构造函数(例如new,malloc,HeapAlloc)来获得堆内存后,但是没有释放而导致的泄漏问题。我们的行情服务器是一个长期运行在客户服务器上的应用程序,如果存在内存泄漏,那么当内存增长到某个值时,会极大地影响当前机器的性能,直至影响我们的行情服务程序,甚至由于内存已不够而导致的程序崩溃。因此我们需要掌握内存泄漏问题的基本调试技巧,本文对windbg调试内存泄漏问题做一个简单的介绍。
以下面这个代码为例:
#include <iostream>
#include <windows.h>
int main()
{
do
{
char *p = new char[1024];
Sleep(1);
} while (1);
std::cout << "Hello World!\n";
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
先进行windbg环境的配置:
1)配置windows符号服务器SRVd:\symbolshttp://msdl.microsoft.com/download/symbols
2)将当前程序的pdb文件路径加入到Windbg的Symbol File Path路径中
3)配置操作系统的标志,以便为内存泄漏的进程启用用户堆栈跟踪。可以通过安装Windbg自带的gflags.exe程序,通过命令“gflags.exe -i 20190718.exe +ust”来完成,20190718.exe是程序名(不用带路径,只用输入程序名即可)
准备工作完成后,开始进行一步步来调试: 1, 启动20190718.exe程序,使用Windbg的Attach To Process附加上去(或者通过Open Excutable直接打开)
2, 附加进程后,输入“!heap –s”命令。-s代表统计信息,可以查看当前进程的所有堆分配信息:
此时只有一个堆02d40000(这个堆是CRT堆)。
3, F5让程序继续运行一会儿,然后中断(Windbg-Debug-Break菜单),再次输入“!heap –s”命令:
可以看到02d40000堆上分配的内存有增加。(reserv是堆段上的保留内存–未被使用的,而应用进程所使用的内存都是从commit中取得,因此我们只需要对比commit内存即可)
4, 再输入“!heap -stat -h 02d40000”命令,查看正在增长的堆的堆统计信息:
-stat命令能够给出关于一个或者多个堆的使用统计信息,包括分配内存的大小,这个大小的堆块的个数以及总共的大小,最后是当前处于“busy”(占用)状态的堆块所占百分比。默认情况下,-stat按照总量大小来排序。
上面的快照显示正在分配的400(十六进制)大小的堆块有0x5acf个,且堆块所占百分比达到了99.77%,这些数据使我们推测大小为400(十六进制)bytes的内存存在泄漏的可能(也刚好是代码中分配的1024字节)。
5, 输入“!heap –flt s 400”,查看堆上所有大小为400的blocks信息:
6, 输入“!heap –p –a UserPtr”命令,UserPtr为上面的任何一个地址,比如!heap -p -a 047b8e70,显示地址047b8e70的调用堆栈信息:
从调用堆栈中可以看到,!main+0x0000001a地址处的代码可能导致内存泄漏。
7, 输入“lsa !main+0x0000001a”转到具体代码处:
参考文献:
1,《Windows高级调试》第九章第五节
2, https://www.codeproject.com/Articles/31382/Memory-Leak-Detection-Using-Windbg
from:https://blog.csdn.net/bajianxiaofendui/article/details/96590223