如何找到死锁?
How to find a deadlock?
我正在尝试按照 this Microsoft link 中解释的程序查找我的应用程序中可能存在的死锁。
在我的例子中,我也从函数 !locks
:
开始
CritSec +1130780 at 01130780
WaiterWoken No
LockCount 0
RecursionCount 1
OwningThread 1624
EntryCount 0
ContentionCount 8
*** Locked
CritSec Wldap32!SelectLock1+0 at 7630a1b0
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 30d8
EntryCount 0
ContentionCount 219
*** Locked
CritSec Wldap32!SelectLock2+0 at 7630a168
WaiterWoken No
LockCount 0
RecursionCount 1
OwningThread 1624
EntryCount 0
ContentionCount 47d
*** Locked
CritSec +cd6838 at 00cd6838
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 4584
EntryCount 0
ContentionCount 184
*** Locked
Scanned 107 critical sections
第二项提到我需要去线程30d8
:
0:000> ~
...
59 Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
...
因此,我可能希望获得有关线程 59 中关键部分的信息,但在查看时:
59 Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
# ChildEBP RetAddr Args to Child
00 0a48f4c4 74de9220 000036b8 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
01 0a48f574 74df376d 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2Ex+0x208
02 0a48f5ac 74df37a7 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2+0x2d
03 0a48f5e0 76303545 0d7acba0 bdd2500a 0a48f61f IPHLPAPI!IcmpSendEcho+0x27
04 0a48f6c0 762e0a46 0a48f79c 0c2180a0 0a08d660 Wldap32!LdapPingServer+0xa1
05 0a48f708 762c4ca0 00001363 0c3f2ba0 00000000 Wldap32!DrainWinsock+0x1c69a
06 0a48f778 762c6eae 00002774 00000000 0a48f79c Wldap32!LdapWaitForResponseFromServer+0x767
07 0a48f7d0 762c7bf9 00000000 0a48f850 0a48f9d4 Wldap32!ldap_result_with_error+0xf2
08 0a48f7f8 002c3a9b 0a08d88c 00001363 00000000 Wldap32!ldap_result+0x59
09 0a48faf8 002bcc1e 04059930 569939a1 00c21220 <Application>!CActiveDirectoryInfo::LDAPNotificationFunc+0xe5b
0a 0a48fb24 002c41a0 04059930 569939e5 7437f28e <Application>!CActiveDirectoryInfo::LDAPNotification_Protected+0xbe
0b 0a48fb60 7437f2e9 04059930 22a3f765 7437f28e <Application>!LDAPNotification+0x50
0c 0a48fb98 7437f2cd 7437f28e 0a48fbb8 75547c04 msvcr110!_beginthreadex+0xb4
0d 0a48fba4 75547c04 026f2b28 75547be0 238314af msvcr110!_endthreadex+0x102
0e 0a48fbb8 77d9ad2f 026f2b28 21045533 00000000 kernel32!BaseThreadInitThunk+0x24
0f 0a48fc00 77d9acfa ffffffff 77d800c7 00000000 ntdll!__RtlUserThreadStart+0x2f
10 0a48fc10 00000000 7437f28e 026f2b28 00000000 ntdll!_RtlUserThreadStart+0x1b
第一条评论后编辑:
不幸的是,命令 sosex.dlk
没有显示任何信息,即使在 运行 !bhi
命令之后也是如此。
就调查36b8
而言,也没有太多信息:
0:000> !handle 36b8 f
Handle 000036b8
Type Event
Attributes 0
GrantedAccess 0x1f0003:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState,ModifyState
HandleCount 2
PointerCount 65538
Name <none>
Object specific information
Event Type Auto Reset
Event is Waiting
我不知道 !findstack
功能,你能告诉我我做错了什么吗?
0:000> !findstack CriticalSection
0:000> !findstack *!CriticalSection
0:000> !findstack RtlEnterCriticalSection
0:000> !findstack *CriticalSection*
=> always no results.
线程 59 已经拥有临界区。这意味着它在前一段时间调用了 EnterCriticalSection
。您将不会再在调试器中看到它。该线程 应该 在某个时候调用 LeaveCriticalSection
。但目前它正在等待其他事情发生(WaitForSingleObject
on object 36b8
)。
后续步骤:
- 找出
36b8
是什么,使用 !handle 36b8 f
。
- 与 59 不同的线程可能正在该临界区等待。所以当心
EnterCriticalSection
使用 !findstack
.
如果您怀疑死锁只是由临界区引起的,您可以使用!sosex.dlk
。虽然 SOSEX 是为 .NET 死锁设计的,但它也可以检测关键部分的死锁。
您应该考虑关闭 ldap 连接对象上的 ping。如果您正在调用此调用堆栈,则通常意味着 ICMP/ping 在您的域控制器和调用应用程序服务器之间不起作用(您可以使用应用程序服务器的 ping 命令行工具对此进行测试;如果该工具挂起或超时,您的挂起与应用程序相同。
如果您不拥有进行底层 ldap 调用的库,则应将您的网络设置为允许或拒绝 ping,而不是丢弃它们。
我正在尝试按照 this Microsoft link 中解释的程序查找我的应用程序中可能存在的死锁。
在我的例子中,我也从函数 !locks
:
CritSec +1130780 at 01130780
WaiterWoken No
LockCount 0
RecursionCount 1
OwningThread 1624
EntryCount 0
ContentionCount 8
*** Locked
CritSec Wldap32!SelectLock1+0 at 7630a1b0
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 30d8
EntryCount 0
ContentionCount 219
*** Locked
CritSec Wldap32!SelectLock2+0 at 7630a168
WaiterWoken No
LockCount 0
RecursionCount 1
OwningThread 1624
EntryCount 0
ContentionCount 47d
*** Locked
CritSec +cd6838 at 00cd6838
WaiterWoken No
LockCount 1
RecursionCount 1
OwningThread 4584
EntryCount 0
ContentionCount 184
*** Locked
Scanned 107 critical sections
第二项提到我需要去线程30d8
:
0:000> ~
...
59 Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
...
因此,我可能希望获得有关线程 59 中关键部分的信息,但在查看时:
59 Id: 3ff4.30d8 Suspend: 0 Teb: fe2a5000 Unfrozen
# ChildEBP RetAddr Args to Child
00 0a48f4c4 74de9220 000036b8 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
01 0a48f574 74df376d 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2Ex+0x208
02 0a48f5ac 74df37a7 0d7acba0 00000000 00000000 IPHLPAPI!IcmpSendEcho2+0x2d
03 0a48f5e0 76303545 0d7acba0 bdd2500a 0a48f61f IPHLPAPI!IcmpSendEcho+0x27
04 0a48f6c0 762e0a46 0a48f79c 0c2180a0 0a08d660 Wldap32!LdapPingServer+0xa1
05 0a48f708 762c4ca0 00001363 0c3f2ba0 00000000 Wldap32!DrainWinsock+0x1c69a
06 0a48f778 762c6eae 00002774 00000000 0a48f79c Wldap32!LdapWaitForResponseFromServer+0x767
07 0a48f7d0 762c7bf9 00000000 0a48f850 0a48f9d4 Wldap32!ldap_result_with_error+0xf2
08 0a48f7f8 002c3a9b 0a08d88c 00001363 00000000 Wldap32!ldap_result+0x59
09 0a48faf8 002bcc1e 04059930 569939a1 00c21220 <Application>!CActiveDirectoryInfo::LDAPNotificationFunc+0xe5b
0a 0a48fb24 002c41a0 04059930 569939e5 7437f28e <Application>!CActiveDirectoryInfo::LDAPNotification_Protected+0xbe
0b 0a48fb60 7437f2e9 04059930 22a3f765 7437f28e <Application>!LDAPNotification+0x50
0c 0a48fb98 7437f2cd 7437f28e 0a48fbb8 75547c04 msvcr110!_beginthreadex+0xb4
0d 0a48fba4 75547c04 026f2b28 75547be0 238314af msvcr110!_endthreadex+0x102
0e 0a48fbb8 77d9ad2f 026f2b28 21045533 00000000 kernel32!BaseThreadInitThunk+0x24
0f 0a48fc00 77d9acfa ffffffff 77d800c7 00000000 ntdll!__RtlUserThreadStart+0x2f
10 0a48fc10 00000000 7437f28e 026f2b28 00000000 ntdll!_RtlUserThreadStart+0x1b
第一条评论后编辑:
不幸的是,命令 sosex.dlk
没有显示任何信息,即使在 运行 !bhi
命令之后也是如此。
就调查36b8
而言,也没有太多信息:
0:000> !handle 36b8 f
Handle 000036b8
Type Event
Attributes 0
GrantedAccess 0x1f0003:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState,ModifyState
HandleCount 2
PointerCount 65538
Name <none>
Object specific information
Event Type Auto Reset
Event is Waiting
我不知道 !findstack
功能,你能告诉我我做错了什么吗?
0:000> !findstack CriticalSection
0:000> !findstack *!CriticalSection
0:000> !findstack RtlEnterCriticalSection
0:000> !findstack *CriticalSection*
=> always no results.
线程 59 已经拥有临界区。这意味着它在前一段时间调用了 EnterCriticalSection
。您将不会再在调试器中看到它。该线程 应该 在某个时候调用 LeaveCriticalSection
。但目前它正在等待其他事情发生(WaitForSingleObject
on object 36b8
)。
后续步骤:
- 找出
36b8
是什么,使用!handle 36b8 f
。 - 与 59 不同的线程可能正在该临界区等待。所以当心
EnterCriticalSection
使用!findstack
.
如果您怀疑死锁只是由临界区引起的,您可以使用!sosex.dlk
。虽然 SOSEX 是为 .NET 死锁设计的,但它也可以检测关键部分的死锁。
您应该考虑关闭 ldap 连接对象上的 ping。如果您正在调用此调用堆栈,则通常意味着 ICMP/ping 在您的域控制器和调用应用程序服务器之间不起作用(您可以使用应用程序服务器的 ping 命令行工具对此进行测试;如果该工具挂起或超时,您的挂起与应用程序相同。
如果您不拥有进行底层 ldap 调用的库,则应将您的网络设置为允许或拒绝 ping,而不是丢弃它们。