【问题标题】:Windbg get value from dictionary using TryGetValueWindbg 使用 TryGetValue 从字典中获取值
【发布时间】:2015-03-13 22:32:44
【问题描述】:

我有一个 IIS 进程的转储,它消耗了几乎 100% 的 CPU。我运行windbg,在运行!runaway 命令后,我发现最上面的线程都卡在了Dictionary FindEntry(System.__Canon) 命令中。这些线程之一的堆栈以:

0:043> !clrstack -p
OS Thread Id: 0x1740 (43)
        Child SP               IP Call Site
0000008646eecc78 00007ff810530c8a [RedirectedThreadFrame: 0000008646eecc78] 
0000008646eecd10 00007ffffe420ccd System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon)
    PARAMETERS:
        this = <no data>
        key = <no data>

0000008646eecd80 00007ffffe422ed4 System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].TryGetValue(System.__Canon, System.__Canon ByRef)
    PARAMETERS:
        this = <no data>
        key = <no data>
        value = <no data>

我怀疑我的问题类似于this one,但我需要更多证据才能得出结论。为此,我希望我可以获得有关字典的值或任何其他信息。看这段代码,与网络上的大多数教程有两点不同:

  1. 参数显示为System.__Canon。这是什么意思?
  2. 如何从TryGetValue 中获取值,因为它只有对输出的引用 (ByRef),并且指针未列在“参数”部分。

提前致谢!

【问题讨论】:

标签: c# dictionary windbg


【解决方案1】:

您尚未共享源代码,也未编写是否使用静态字典,所以我假设您没有。但是您怀疑您的字典在线程之间共享 - 让我们找出答案。 CLRStack 在方法中间或者代码高度优化时经常找不到参数。另一个非常有用的 SOS 命令是 !DumpStackObjects!dso。它只是转储堆栈上的所有托管对象。您可能会在那里找到您的键值(除非它是基本类型 - 然后事情会变得有点复杂,我需要更多信息来帮助您)。示例输出可能如下所示:

OS Thread Id: 0x1520 (0)
ESP/REG  Object   Name
ecx      020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
edx      020e218c System.String    k1
esi      020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
005BED6C 020e1228 System.String    
005BED70 020e218c System.String    k1
005BED78 020e45a4 System.IO.TextReader+SyncTextReader
005BED80 020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
005BED90 020e217c System.Object[]    (System.String[])
005BEDA0 020e1228 System.String    
005BEDA4 020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
005BEDA8 020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
005BEDAC 020e21b4 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String, mscorlib]]
005BEDB8 020e21a0 System.String    v1
005BEDBC 020e217c System.Object[]    (System.String[])
005BEE40 020e217c System.Object[]    (System.String[])
005BEFA4 020e217c System.Object[]    (System.String[])
005BEFD4 020e217c System.Object[]    (System.String[])

请注意字典在列表中。为每个线程运行此命令并验证它们是否共享字典地址。 System.__Canon 不是你应该担心的——它只是泛型类型中的一个占位符 (http://referencesource.microsoft.com/#mscorlib/system/object.cs,a210e11a9e5f2deb)。在上面的输出中,我有一个 Dictionary&lt;String,String&gt; 实例并且正在寻找 k1 - 你可以看到它也在堆栈中。

【讨论】:

  • 您可以使用~*e!dso 在所有线程上运行该命令。它可能会在纯本机堆栈上失败。
  • @lowleveldesign 感谢您的回复。我没有分享具体细节,因为我没有源代码(我只有 IIS 的完整转储)。我查看了前 3 个线程,它们确实共享同一个字典地址。建立连接并声明字典搜索是挂起过程的罪魁祸首的最佳方法是什么?我可以用“!runaway”看到每个线程的总时间,但是有没有办法找到每个线程实际上卡在同一行的时间?
  • @tyron 不幸的是,您无法确定给定方法何时开始(这是您通常使用实时调试或日志的目的)。如果多个线程的调用堆栈上有 FindEntry 方法(这是您的情况),则字典搜索是罪魁祸首。通常,当您观察到 CPU 节流时,您会进行几次转储,每次转储之间会有一些延迟(几秒钟)。然后您比较转储以确保给定方法是问题所在。如果你只有一个转储,你就剩下一些猜测了。
  • 我明白你的意思,肯定会有多个转储。下次我会这样做。顺便说一句,你提到你有Dictionary&lt;String,String&gt;,然后你可以照顾“k1”。我的情况,我猜有 Dictionary&lt;Canon,Canon&gt; ,对吧?到那时我有没有机会找到变量值? thiskey 在我的示例中都显示“”,所以我无法在 !dso 上显示 :(
  • 不,!dso 将向您显示堆栈上所有可用的托管对象 - 很可能存在密钥。佳能只是一个占位符类型。如果找不到,则需要分析在当前指令指针(线程停止的地方)之前执行的汇编代码,并找出传递给方法的值在哪里(一开始可能是在 RDX 注册表中)。
猜你喜欢
  • 2013-07-16
  • 2022-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-04
  • 2016-05-09
相关资源
最近更新 更多