DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

posted on 2021-02-06 14:31  DoubleLi  阅读(482)  评论(0编辑  收藏  举报