今天遇到了一个应用程序死锁了,由于是在测试人员的环境中,所以生成了一个dump文件,生成dump文件的方法可以用任务管理器,在任务管理器的进程列表中点击右键,选择“Create Dump File”,就会为该进程生成一个mini dump文件。
由于是自己的程序,所以一般进程对应的pdb文件和源代码文件都有。下面以visual studio 2010和windbg分别说明如何定位到死锁代码。
(1)windbg方法。
因为我们猜测该程序死锁了,所以用windbg打开dump文件,同时设置符号路径,执行步骤
第一步:执行命令!locks
结果如下:
0:000> !locks
CritSec +13a8e18 at 00000000013a8e18
WaiterWoken No
LockCount 9
RecursionCount 1
OwningThread f34
EntryCount 0
ContentionCount 9
*** Locked
Scanned 31 critical sections
请注意 Owning Thread f34和***Locked.表明线程f34在等待所。
第二步:执行~命令,结果如下:
0:000> ~
. 0 Id: 1614.16b8 Suspend: 0 Teb: 00007ff7`b4cbd000 Unfrozen
1 Id: 1614.ff0 Suspend: 0 Teb: 00007ff7`b4cb9000 Unfrozen
2 Id: 1614.a94 Suspend: 0 Teb: 00007ff7`b4cb7000 Unfrozen
3 Id: 1614.f34 Suspend: 0 Teb: 00007ff7`b4b8e000 Unfrozen
4 Id: 1614.1370 Suspend: 0 Teb: 00007ff7`b4b8c000 Unfrozen
5 Id: 1614.4ac Suspend: 0 Teb: 00007ff7`b4b8a000 Unfrozen
6 Id: 1614.1054 Suspend: 0 Teb: 00007ff7`b4b88000 Unfrozen
7 Id: 1614.76c Suspend: 0 Teb: 00007ff7`b4b86000 Unfrozen
8 Id: 1614.b70 Suspend: 0 Teb: 00007ff7`b4b84000 Unfrozen
9 Id: 1614.1ad0 Suspend: 0 Teb: 00007ff7`b4b80000 Unfrozen
10 Id: 1614.184c Suspend: 0 Teb: 00007ff7`b4cb5000 Unfrozen
11 Id: 1614.114c Suspend: 0 Teb: 00007ff7`b4cb3000 Unfrozen
12 Id: 1614.161c Suspend: 0 Teb: 00007ff7`b4b7e000 Unfrozen
13 Id: 1614.17b8 Suspend: 0 Teb: 00007ff7`b4cbb000 Unfrozen
14 Id: 1614.15c Suspend: 0 Teb: 00007ff7`b4b82000 Unfrozen
15 Id: 1614.1900 Suspend: 0 Teb: 00007ff7`b4b7c000 Unfrozen
16 Id: 1614.c6c Suspend: 0 Teb: 00007ff7`b4b7a000 Unfrozen
17 Id: 1614.17cc Suspend: 0 Teb: 00007ff7`b4b78000 Unfrozen
找到f34线程的编码为3
第三步:执行命令 ~3 kb查看3号线程堆栈,结果如下:
0:000> ~3 kb
RetAddr : Args to Child : Call Site
00007ffa`ab1c1148 : 00000000`01551080 00000000`00010100 ffffffff`fffffffe 00000000`00000000 : ntdll!ZwWaitForSingleObject+0xa
00007ffa`a63c6ea0 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000344 : KERNELBASE!WaitForSingleObjectEx+0x94
果然在等待锁。
这就找到了死锁位置,但是往往并不是仅仅因为这里代码的问题,而是还有另外一个地方在使用锁不正确导致的。
2)用visual studio 2010
第一步:和windbg方法一样,打开dump文件,配置符号路径,通常还需要load系统库的符号,因为默认没有系统库文件的调试符号。
第二步:vc中并没有像windbg那样的命令!locks来显示锁的情况,只能靠自己分析了。但是也提供了一个很不错的方法,点击“debug"菜单,选择”窗口“子菜单,再选择”parallel stacks“菜单,会显示所有的线程及其堆栈,如同windbg的~* kb命令一样,非常有用。如图所示:
第三步:慢慢分析,看看哪些线程在等待锁,和windbg一样,也可以很快发现死锁的位置。