导航

[转] Windbg调试技巧收集

Posted on 2011-04-22 18:18  口渴的火麒麟  阅读(391)  评论(0编辑  收藏  举报

/******************high CPU check**************************/
!threadpool
.time
!runaway --all thread run time.
~[thead id]s
k        --heap check
!clrstack
!savemodule [address] [filename] --address from below
!dumpdomain

/****************command list******************/
lm //查看加载了哪些模块
   .load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll //加载调试模块
   ld TestClass //加载调试符号
   !name2ee TestClass.exe TestClass.Program.test //显示test方法相关的地址
   !dumpmt -md 00976d48 //得到类的成员函数详细信息
   !dumpil 00973028 // 显示这个方法被编译器编译之后的IL代码
   !dumpheap -stat //该命令显示程序中所有对象的统计信息,显示的大小是对象本身的大小,不包括对象里面值的大小
   !dumpheap -mt 790fcb30 //该命令显示MethodTable 790fcb30的详细信息
   !gcroot 012919b8 //来显示一个实例的所属关系
   !dumpobj(do) 012a3904 //显示一个对象的具体内容,看对象里面有什么,值是什么
   !ObjSize 012a1ba4 //对象实际在内存中的大小
   !eeheap -gc //查看托管堆的情况(包括大小)
   !DumpArray //查看数组信息

【调试死锁】
1、!syncblk,查看哪些线程拿到了锁
2、~67e!clrstack 跳到某个拿到锁的线程看它正在干什么操作,迟迟不肯释放锁
3、!runaway 查看这个占有锁的线程运行了多长时间。
4、~*e!clrstack查看所有线程的托管堆栈,看看哪些是正在等待锁的,比如hang在System.Threading.Monitor.Enter(System.Object)
5、~136s选择该线程,显示如下
0:000> ~136s eax=00005763 ebx=08deeb5c ecx=03eff0d4 edx=5570ab69 esi=08deeb5c edi=7ffd6000 eip=7c95ed54 esp=08deeb10 ebp=08deebb8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 7c95ed54 c3 ret
找到ecx寄存器的值,复制后ctrl+f,向上查找,会找到!syncblk的地方,如下
0:000> !syncblk Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner 1906 03ee4be4 5 1 03ee8f88 22c8 67 185e2ef0 System.Object 5390 052ca39c 3 1 05292b30 1dd4 49 1060d3ac System.Object 9372 0530702c 15 1 0012d3a8 1aa8 80 185e7704 System.Object 11428 03eff0d4 35 1 053b8fa8 169c 120 166acd98 System.Object 15278 0531c6b4 61 1 06bc1430 26d8 86 1a5bea88 System.Object
可以看到136线程等待的锁被120号线程占着不放(格式有点乱,凑合看),
6、有时候通过ecx寄存器找锁不是很确定,可以用~* kb来把所有线程堆栈打出来,然后根据!syncblk出来的同步快的值去搜索大概有多少个线程在等那个锁。因为同样是等待锁,可等的状态不一样,有的在Q里,有的锁已经升级,有的去尝试去拿锁了,所以不一定当时ecx寄存器指向那块内存,具体如何找到某个正在等待锁的线程等待的锁的内存地址,以及它正等待的这个锁被哪个线程拿着,我还没琢磨出规律来,但一般情况下,如果有其它同步对象的话,更难查。.net里用我上面说的几步就能查出锁的问题了。

【内存泄漏】
1、!dumpheap -stat看看哪些对象个数最多,占内存最大,
2、找到某个格式比较多的对象,可以看它的方法表,然后用!dumpheap -mt 66398fa4去随机找几个对象的地址
3、用!do 1e5a22bc命令去查看几个对象的状态,属性的值等,看看正常不正常
4、用!gcroot -nostacks 1e5a22bc去查看几个对象的根正常不正常,如果有些对象的根不是自己预先设计的那样,很可能被自己没想到的对象强引用了,所以GC无法回收它,就泄漏了。

1、!eestack -short -ee查看所有重要(获取锁的,托管的,停止并允许回收的)线程的dumpstack,差不多相当于~*e!dumpstack
2、.time 可以看到进程跑了多少时间
3、!dso 查看当前线程里有哪些对象,分析内存泄漏问题也许会用到

1、!analyze -v :用于分析挂掉线程的详细情形,错误原因。
2、!locks :列出全部资源使用情况。
3、!locks -v 0x???????? :特定地址的死锁分析。
4、!thread 0x????????:特定线程详情。
5、.thread 0x????????:转到某个线程堆栈。