使用 Windbg 进行临界区挂起分析
Critical section hang analysis with Windbg
当我的应用程序有一段时间没有响应时,我最近得到了一个通过 procdump 生成的转储文件。
当我 运行 !locks 转储文件时,我得到一个单独的条目,类似于:
0:000> !locks
CritSec +123456 at 00123456
WaiterWoken No
LockCount 0
RecursionCount 2
OwningThread aaaa
EntryCount 0
ContentionCount 0
*** Locked
就是那个列表。就这样。当我进一步深入研究时:
0:000> dt RTL_CRITICAL_SECTION 00123456
MyModule!RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0x00aabbcc _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-2
+0x008 RecursionCount : 0n2
+0x00c OwningThread : 0x0000aaaa Void
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0
问题:
1) 我是否应该将 MyModule!RTL_CRITICAL_SECTION
作为确定的线索,这个关键部分可能在 MyModule 中定义?
2) 有没有办法让Windbg显示这个临界区的实际变量名? (即假设#1 为真并且这是一个 CS 应用程序代码 defined/access。)
3) 为什么上述列表中的 LockCount 值彼此不一致? (一个是0,另一个是-2。)
4) 我想我很了解 LockCount,知道它不能低于 -1。更不用说 RecursionCount 似乎与 LockCount 严重脱节。
我想最重要的问题是我是否应该将其归因于损坏的 CS?
我可以使用示例应用程序轻松重现负 LockCount 的影响,这是我的答案:
对您问题的回应
关于 1)
Should I take MyModule!RTL_CRITICAL_SECTION as definitive clue this critical section is probably defined inside MyModule?
是的,这是您对临界区的定义,可能符合也可能不符合微软的定义。要使用 Microsoft 的定义,请使用 dt nt!_RTL_CRITICAL_SECTION
关于 2)
Is there a way to make Windbg display the actual variable name of this critical section? (i.e assuming #1 is true and this is a CS the application code has defined/access to.)
是的,如果它被调用堆栈上的函数使用。使用 .frame
,导航到 frme,使用 ?? variableName
显示变量,例如
0:000> k L2
# ChildEBP RetAddr
00 0116faa4 00d67419 KERNELBASE!DebugBreak+0x2
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109
0:000> .frame 1
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109 [c:\users\t\documents\visual studio 2015\projects\criticalsectionleavetwice\criticalsectionleavetwice\criticalsectionleavetwice.cpp @ 24]
0:000> ?? CriticalSection
struct _RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0xffffffff _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-2
+0x008 RecursionCount : 0n2
+0x00c OwningThread : 0x00000d6c Void
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0x20007d0
关于 3)
Why do the LockCount values in the aforementioned listings at odds with each other? (one has 0 and the other has -2.)
字段 LockCount
不再是真正的锁定计数,如中所述
this answer。相关部分:
In Microsoft Windows Server 2003 Service Pack 1 and later versions of Windows, the LockCount field is parsed as follows:
- The lowest bit shows the lock status. If this bit is 0, the critical section is locked; if it is 1, the critical section is not locked.
- The next bit shows whether a thread has been woken for this lock. If this bit is 0, then a thread has been woken for this lock; if it is 1, no thread has been woken.
- The remaining bits are the ones-complement of the number of threads waiting for the lock.
恕我直言,!locks
命令应该为您进行解释。
-2
的特定值在二进制中是11111111 ... 1111110
,所以最后一位是0,意味着临界区被锁定。之前的位是 1,所以没有线程被唤醒。余数的补数为0,对应!locks
.
的锁计数输出
这意味着,您分析的关键部分没有涉及死锁。
关于 4)
I think I understand LockCount well enough to know it can't go below -1. Not to mention RecursionCount seems to be badly out of step with LockCount.
参见 #3。
关于未编号的问题 5)
should I just chalk this up to corrupted CS?
没有。它似乎没有损坏。
使用 !dlk 进行死锁分析
要检查死锁是否由它引起,我建议使用 sosex's (download) !dlk
命令。虽然它主要是 .NET 的扩展,但我曾要求即使没有 .NET 也能使其适用于关键部分 - 并且该功能已在 SOSex 的较新版本之一中实现。
如果找不到 .NET,它会输出有关该事实的警告,然后继续分析关键部分:
在您的情况下可能如下所示:
0:000> !dlk
Unable to initialize .NET data interface. The CLR has not yet been loaded in the process (mscorwks/clr module not loaded).
Examining CriticalSections...
No deadlocks detected.
用法:
.load c:\path\to\sosex.dll
!dlk
如果它识别出死锁,则非常容易阅读。如果没有,您仍然需要应用其他技术,即不能保证没有其他类型的死锁(例如,如果等待链包含其他类型的同步对象,如线程、事件等)。
示例输出(不适用于关键部分,但类似):
0:010> !dlk
Deadlock detected:
CLR thread 4 holds sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
waits sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
CLR thread 5 holds sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
waits sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
CLR Thread 4 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
CLR Thread 5 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
1 deadlock detected.
挂起分析
!analyze -hang
和 Debug Diag 可能有助于挂起分析。
当我的应用程序有一段时间没有响应时,我最近得到了一个通过 procdump 生成的转储文件。
当我 运行 !locks 转储文件时,我得到一个单独的条目,类似于:
0:000> !locks
CritSec +123456 at 00123456
WaiterWoken No
LockCount 0
RecursionCount 2
OwningThread aaaa
EntryCount 0
ContentionCount 0
*** Locked
就是那个列表。就这样。当我进一步深入研究时:
0:000> dt RTL_CRITICAL_SECTION 00123456
MyModule!RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0x00aabbcc _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-2
+0x008 RecursionCount : 0n2
+0x00c OwningThread : 0x0000aaaa Void
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0
问题:
1) 我是否应该将 MyModule!RTL_CRITICAL_SECTION
作为确定的线索,这个关键部分可能在 MyModule 中定义?
2) 有没有办法让Windbg显示这个临界区的实际变量名? (即假设#1 为真并且这是一个 CS 应用程序代码 defined/access。)
3) 为什么上述列表中的 LockCount 值彼此不一致? (一个是0,另一个是-2。)
4) 我想我很了解 LockCount,知道它不能低于 -1。更不用说 RecursionCount 似乎与 LockCount 严重脱节。
我想最重要的问题是我是否应该将其归因于损坏的 CS?
我可以使用示例应用程序轻松重现负 LockCount 的影响,这是我的答案:
对您问题的回应
关于 1)
Should I take MyModule!RTL_CRITICAL_SECTION as definitive clue this critical section is probably defined inside MyModule?
是的,这是您对临界区的定义,可能符合也可能不符合微软的定义。要使用 Microsoft 的定义,请使用 dt nt!_RTL_CRITICAL_SECTION
关于 2)
Is there a way to make Windbg display the actual variable name of this critical section? (i.e assuming #1 is true and this is a CS the application code has defined/access to.)
是的,如果它被调用堆栈上的函数使用。使用 .frame
,导航到 frme,使用 ?? variableName
显示变量,例如
0:000> k L2
# ChildEBP RetAddr
00 0116faa4 00d67419 KERNELBASE!DebugBreak+0x2
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109
0:000> .frame 1
01 0116fc5c 00d67ebe CriticalSectionLeaveTwice!main+0x109 [c:\users\t\documents\visual studio 2015\projects\criticalsectionleavetwice\criticalsectionleavetwice\criticalsectionleavetwice.cpp @ 24]
0:000> ?? CriticalSection
struct _RTL_CRITICAL_SECTION
+0x000 DebugInfo : 0xffffffff _RTL_CRITICAL_SECTION_DEBUG
+0x004 LockCount : 0n-2
+0x008 RecursionCount : 0n2
+0x00c OwningThread : 0x00000d6c Void
+0x010 LockSemaphore : (null)
+0x014 SpinCount : 0x20007d0
关于 3)
Why do the LockCount values in the aforementioned listings at odds with each other? (one has 0 and the other has -2.)
字段 LockCount
不再是真正的锁定计数,如中所述
this answer。相关部分:
In Microsoft Windows Server 2003 Service Pack 1 and later versions of Windows, the LockCount field is parsed as follows:
- The lowest bit shows the lock status. If this bit is 0, the critical section is locked; if it is 1, the critical section is not locked.
- The next bit shows whether a thread has been woken for this lock. If this bit is 0, then a thread has been woken for this lock; if it is 1, no thread has been woken.
- The remaining bits are the ones-complement of the number of threads waiting for the lock.
恕我直言,!locks
命令应该为您进行解释。
-2
的特定值在二进制中是11111111 ... 1111110
,所以最后一位是0,意味着临界区被锁定。之前的位是 1,所以没有线程被唤醒。余数的补数为0,对应!locks
.
这意味着,您分析的关键部分没有涉及死锁。
关于 4)
I think I understand LockCount well enough to know it can't go below -1. Not to mention RecursionCount seems to be badly out of step with LockCount.
参见 #3。
关于未编号的问题 5)
should I just chalk this up to corrupted CS?
没有。它似乎没有损坏。
使用 !dlk 进行死锁分析
要检查死锁是否由它引起,我建议使用 sosex's (download) !dlk
命令。虽然它主要是 .NET 的扩展,但我曾要求即使没有 .NET 也能使其适用于关键部分 - 并且该功能已在 SOSex 的较新版本之一中实现。
如果找不到 .NET,它会输出有关该事实的警告,然后继续分析关键部分:
在您的情况下可能如下所示:
0:000> !dlk
Unable to initialize .NET data interface. The CLR has not yet been loaded in the process (mscorwks/clr module not loaded).
Examining CriticalSections...
No deadlocks detected.
用法:
.load c:\path\to\sosex.dll
!dlk
如果它识别出死锁,则非常容易阅读。如果没有,您仍然需要应用其他技术,即不能保证没有其他类型的死锁(例如,如果等待链包含其他类型的同步对象,如线程、事件等)。
示例输出(不适用于关键部分,但类似):
0:010> !dlk
Deadlock detected:
CLR thread 4 holds sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
waits sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
CLR thread 5 holds sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
waits sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
CLR Thread 4 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
CLR Thread 5 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
1 deadlock detected.
挂起分析
!analyze -hang
和 Debug Diag 可能有助于挂起分析。