windbg查询内存泄笔记

前段时间一直在做项目的压力测试,奈何天意弄人,测试一直在出问题,从数据库,到服务器cpu,再到内存,不停地在调试,检测,修改,再调试。

下面就将windbg的使用心得总结下。

 

1:先要下dump,为了分析内存泄露,至少要下好几个dump比较。

2:下完dump后,就可以使用windbg打开该dump了,使用!dumpheap -stat命令,分析其中的内存分布,比较各个dump的可疑之处。初步确认几个可疑的内存泄露。

3:确认可疑泄露支出后,使用!dumpheap -type 命令,以及!gcroot,查询泄露的出处。

4:检查上一步的几个源码,分析内存泄露。

1. 什么是windbg

WinDbg从字面意思就是Windows+Debug的组合,即Windows平台上的调试工具,可以调试用户模式、内核模式、dump文件等,总之知道它的调试功能非常强大就行了。WinDbg调试命令分为3种,分别是基本命令、元命令和扩展命令。基本命令和元命令是调试器自带的,元命令总以".“开头,而扩展命令总以”!"开头。

2. 开始设置windbg

.WinDbg默认的设置路径

File -> Settings -> Debugging settings,默认的源码路径、符号路径和缓存路径如下:

设置_NT_SYMBOL_PATH环境变量

设置_NT_SYMBOL_PATH环境变量的值为SRV*D:\mysymbol*https://msdl.microsoft.com/download/symbols:

 

 

 

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debuggercmds/commands

https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/getting-started-with-windbg?source=recommendations

常见非托管命令

1.工具和系统级别类

  • .restart // 重启并调试
  • .kill // 强制结束当前调试
  • q // 结束当前调试会话,回到基础工作空间,并结束调试进程
  • qd // 结束当前调试会话,回到基础工作空间,但不结束调试进程
  • vertarget // os信息
  • !cpuid // cpu信息
  • .time // 获取dump抓取时间
  • ? // 打印出所有标准命令
  • .help // 打印出所有元命令
  • .hh // 打开windbg的chm帮助文件
  • .cls // 清空控制台
  • !analyze -v // 对内存转储文件进行分析,并显示详细的结果

2.进程和线程类

  • | // 列出调试进程
  • |* // 列出调试进程
  • ~ // 列出线程
  • ~* // 所有线程
  • ~* k // 所有线程堆栈信息
  • ~* r // 所有线程寄存器信息
  • ~. // 查看当前线程
  • ~0s // 查看主线程
  • ~N // 查看序数为N的线程
  • ~~[n] // 查看线程ID为n的线程
  • ~N f // 冻结序数为N的线程
  • ~N u // 解冻序数为N的线程
  • ~N n // Suspend序数为N的线程
  • ~N m // Resume序数为N的线程
  • ~* e !gle // 显示所有线程最后的一个错误信息 e后可以为任意windbg命令
  • !runaway //显示当前进程的所有线程时间信息

3. 断点类

  • bl // 列出所有断点
  • bc * // 清除所有断点
  • bc 1 // 清除1号断点
  • bc 1 2 5 // 清除1号、2号、5号断点
  • be * // 启用所有断点
  • be 1 // 启用1号断点
  • bd * // 禁用所有断点
  • bd 1 // 禁用1号断点
  • bp bc701a00 // 在bc701a00地址处放置一个断点
  • bp Test.cpp:36 // 在Test.cpp的36行处放置一个断点
  • bp main // 在main函数的起始处放置一个断点
  • bp Test.cpp:40 ".if (poi(pVar)>5) {}; {g}" // ".if (Condition) {Optional Commands}; {g}" // 条件断点 pVar指针指向的值>5,执行空语句(;),断住 否则继续执行

4. 调试控制类

  • g // Go(F5)
  • gN //【Go with Exception Not Handled】执行gN命令强制让调试器返回没有处理了这个异常,那么系统会进一步分发该异常,
  • gu // 执行到当前函数完成时停下 【Go Up】
  • Ctrl+Break // 暂停正在运行的程序
  • p // 单步执行(F10) 【Step】
  • p 2 // 2为步进数目
  • pc // 执行到下一个函数调用处停下 【Step to Next Call】
  • pa 7c801b0b // 执行到7c801b0b地址处停下 【Step to Adress】
  • t // Step into(F11) 【Trace】
  • tc // 执行到下一个进入点处停下 【Trace to Next Call】
  • ta 7c801b12 // 执行到7c801b12地址处停下 【Trace to Adress】

5. 查看句柄类

  • !handle // 查看所有句柄的ID
  • !handle 000007f8 1 // 查看ID为000007f8的句柄的类型
  • !handle 000007f8 4 // 查看ID为000007f8的句柄的名称
  • !handle 0 5 // 查看所有句柄的类型和名称

6. 线程栈类

  • kb 5 // 只显示最上的5层调用堆栈
  • kv // 在kb的基础上增加了函数调用约定等信息
  • kp // 显示每一层函数调用的完整参数,包括参数类型、名字、取值(必须是完整符号的情况下,private symbols);注意:若程序被优化,这些值不一定对
  • kd // 打印堆栈的地址
  • .frame // 显示当前栈帧
  • .frame n // 设置编号n的栈帧为当前栈帧(n为16进制数)
  • .frame /r n // 设置编号n的栈帧为当前栈帧(n为16进制数) 并显示寄存器变量
  • !uniqstack // 显示所有线程的调用堆栈

7. 汇编和寄存器类

  • u . // 反汇编当前ip寄存器地址的后8条指令
  • u $ip // 反汇编当前ip寄存器地址的后8条指令
  • ub . // 反汇编当前ip寄存器地址的前8条指令
  • ub $ip // 反汇编当前ip寄存器地址的前8条指令
  • u main+0x29 L30 // 反汇编main+0x29地址的后30条指令
  • u // 反编译下8条指令
  • uf CTest::add // 反汇编CTest类的add函数
  • uf /c main // 反汇编main函数,通过/c可以查看main函数中的函数调用(call)都有哪些
  • ub 000c135d L20 // 查看地址为000c135d指令前的20条指令内容
  • r // 显示所有寄存器信息及发生core所在的指令
  • r eax, edx // 显示eax,edx寄存器信息
  • r eax=5, edx=6 // 对寄存器eax赋值为5,edx赋值为6

6. 地址和进制表示类

  • dt // 显示数据结构信息,可以用来查看特定内存地址处的数据结构。
  • hi(x) // 高16 bits
  • low(x) // 低16 bits
  • by(x) // 返回第一个byte
  • wo(x) // 返回第一个word
  • dwo(x) // 返回第一个dword
  • qwo(x) // 返回第一个4 word(Quad-word)
  • poi(x) // 返回第一个指针所指向的值
  • 0n(十进制) 0x (十六进制)0t (8进制) 0y (2进制)

7. 符号模块

  • .sympath // 查看当前符号查找路径
  • .sympath SRVC:\mysymbolshttp://msdl.microsoft.com/download/symbols // 设置本地和远程的符号路径
  • !sym noisy // 激活详细符号加载(noisy symbol loading)显示
  • .reload // 为所有已加载模块载入符号信息
  • ld * // 为所有模块加载符号.symfix
  • ld kernel32 // 加载kernel32.dll的符号
  • lm // 列出所有模块(加载和未加载)对应的符号信息
  • lmv // 列出所有模块(加载和未加载)对应的符号信息

常见托管命令

1. 常用命令

  • !threadpool // 查看线程池CPU使用量
  • !threads // 查看所有托管线程情况
  • !clrstack // 某个线程托管代码的调用栈情况
  • ~*e!clrstack // 所有线程托管代码的调用栈情况
  • !runaway // 查看线程占用CPU时间
  • !dumpstackobjects(!dso) // 本线程调用栈所有对象实例
  • !dumpdomain // 显示所有域里的程序集,或者根据参数获取指定域。
  • !savemodule // 根据具体程序集地址,把当前程序集的代码生成到指定文件
  • !PrintException(!pe) // 显示在当前线程上引发的最后一个异常错误信息
  • !VerifyHeap // 检查垃圾回收器堆中是否有损坏迹象,并显示找到任何错误
  • !syncblk // 显示同步块表信息
  • !dumpheap -stat -type
  • !gcroot
posted @ 2013-08-29 10:35  gavin.huang  阅读(314)  评论(0)    收藏  举报