05-windbg工具定位内存问题-01

windows调试工具系列


 01-windows调试工具(ProcDump使用)

 02-windows调试工具(DebugDiag使用)

 03-windows分析工具(depends定位动态库加载失败问题)

 04-使用windbg调试工具分析-高CPU问题

 05-windbg工具定位内存问题-01


文章目录

  • 简述
  • 问题描述
  • 创建一个dump文件
  • windbg设置符号路径
  • 打开文件DMP文件
  • 分析内存使用情况

简述

  一般针对于总是能复现的内存问题,一般可以在本地使用代码注释的方式,排查内存泄露的具体地方,对于运行很久的一些服务端程序来说,出现内存泄露就需要依赖dump文件来辅助判断下内存泄露的具体地方。本文使用windbg工具来分析生成的dump文件的内存,也可以根据此方法来判断定位内存泄露的问题

问题描述

    前段时间修改过以前一个上线的服务,以前是程序初始化的时候需要加载配置,现在是实时检测配置有没有被修改过,服务更新后一直没有在意,程序正常运行的时候也就40-50M的内存的使用情况,昨天查看的时候,发现内存的使用情况增加了一倍,所以怀疑上次更新的部分代码可能存在了内存泄露的地方,查看了下代码也并未发现异常地方。


一、创建一个dump文件

  本次使用windows的任务管理器来创建一个dump的文件,右击选中的进程,创建转储文件。

二、windbg设置符号路径

  • 设置pdb符号路径:打开windbg,选择File-->Symbol File Path 设置程序的pdb文件和系统的pdb文件,多个pdb文件路径用分号间隔开,例如:
  • c:\Symbols\;SRV*c:\Symbols\*http://msdl.microsoft.com/download/symbols(按照这样设置,WinDbg将先从本地文件夹d:\dev\bin\RelWithDebugInfo\bin\;c:\Symbols\中查找Symbol,如果找不到,则自动从msdn的Symbol Server上下载Symbols到c:\Symbols\文件夹下)。windwos现在已经不在提供符号文件的下载,所以需要远程下载符号文件,

  • 通常个人习惯与把vc依赖的公共的符号文件放到c:\Symbols中,然后项目中的符号文件在单独指向一个符号路径

2.打开文件DMP文件

  • 选择File-->Open Crash Dump 加载dmp文件
  • 加载完成后会显示设定的符号路径加载的pdb文件是否成功。
  • 或者输入命令 lm 能看到pdb文件有没有加载成功,能看到目标模块代码段的起始地址和结束地址,能看到目标模块文件生成时的时间戳
  • 点击module name下面的具体的模块,显示对应的生成的时间戳,同时可以查看到模块的起始地址:

三.分析内存使用情况

  • 使用命令!address -summary 查看内存使用的总量,MEM_COMMIT表示已经提交的内存,表示程序实际占用的物理内存。
  • 继续使用命令 !heap -s 显示内存的使用情况,
  • 通过观察我们可以看到 000000432fee0000堆块占用了大量的内存,但是空闲内存是占了49215k, 提交了101440k,这样算下来,其实内存本身没有问题,多数占用的内存处于空闲状态,那么有可能跟我程序定时扫描数据库中的数据存在关系,所以预留了这么些内存,那还是根据这个DMP简单分析下,windbg查询内存的一些简单方法。继续查看这块堆内存的内存使用情况
    !heap -stat -h 000000432fee0000
  • top20中的内存使用情况,
    • 最多的一个是大小为0x5dccf0的分配次数为1次,这个应该不会产生内存泄露,毕竟就分配了一次内存
    • 第二个是大小为0x78字节的分配次数为0x870e(34574)次数,对于某些常规的内存泄露,某一个类可能分配的内存一直没有释放,那么该类的申请次数肯定很多,然后根据类带下和申请的次数大概计算下泄露的内存的总数,对于分配次数较多的类,先查找下类名,然后再排查代码部分,
  • 根据0x78(120)字节大小,去当前的程序的PDB文件中查找是120个字节大小的结构体,为了能排查此类内存泄露的问题,根据微软提供的例子DIA2Dump(vc的安装目录下存在)和参考了网上的一些例子代码,改善了原因的程序模块,可以遍历当前PDB文件中的各个结构体的大小。DumpTest.exe小程序。执行命令如下,传入pdb文件路径和要查找的结构体大小。如图所示,我程序中定义了一个类 CxxxVideoCam,一个摄像机的类,数据库中实际的摄像机大概是16700多个,现在实际是分配了2次,那么程序还是多分配了一次内存
  • 根据类名,查找整个程序对其分配内存的地方,最终发现,为了方便根据摄像机名称或者摄像机ID快速查找摄像机信息,我创建了两个map,
    std::map<int,CxxxVideoCam*>
    std::map<std::string,CxxxVideoCam*>
    添加map的key-value中,是分别放到了两个函数中实现的,导致再另一个函数中多分配了一次内存,

    总结

    原本想根据dump文件查询内存泄露问题,实际排查发现只是多分配了一次内存,在实际过程中,对于某一块地址空间占用的内存比较高的时候,可以采用此类方法,查看占用内存较多的地址块,然后再分析地址块中分配次数最多的类和结构体,然后扫描类中的PDB文件然后查询对应的类名称,然后再搜索动态申请内存的地方。

猜你喜欢

转载自blog.csdn.net/qq_37103755/article/details/128152002
今日推荐