windbg / sos:查找哪个类具有对象的静态引用

时间:2011-10-20 17:39:14

标签: .net debugging windbg

我正在对内存泄漏进行故障排除,发现一个对象被保存在内存中,因为它被字典引用。当我在字典实例上执行!gcroot时,唯一的固定句柄是System.Object []的数组,它本身是无根的:

0:025> !gcroot -nostacks 38ad01f8
DOMAIN(0000000002287D80):HANDLE(Pinned):11e15c0:Root:  00000000123c5018(System.Object[])->
  0000000002f2ab20(System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[MyApp.MyObject, MyApp]])->
  000000004223e6e0(System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[MyApp.MyObject, MyApp]][])->
  0000000038ad01f8(MyApp.MyObject)

这使我得出结论,Dictionary实例由某个类上的静态字段保存(.NET保留Object数组中的所有静态字段引用)。

但是,现在我被卡住了!因为gcroot和!refs(来自sosex)看不到静态字段引用。

我可以在堆中搜索指向地址2f2ab20的指针:

0:025> s-q 0 L?0xbfffffff 2f2ab20
00000000`123c76f8  00000000`02f2ab20 00000000`02f2ab78

所以我看到地址123c76f8附近的某些结构正在引用我的字典。但是我从哪里开始呢? 123c76f8附近的结构必须由EEClass结构指向,但sos / sosex似乎没有提供解决哪个EEClass相关的方法。

如果没有这些信息,我怎样才能找出哪个对象包含静态字典?

3 个答案:

答案 0 :(得分:3)

进行此类分析的一个选择是使用NuGet上的ClrMD库编写一个小程序来运行转储或进程。

程序看起来像这样:

    DataTarget dataTarget = DataTarget.LoadCrashDump(@"c:\path\to\crash.dmp");
    ClrRuntime runtime = dt.CreateRuntime(@"c:\path\to\mscordacwks.dll");
    ClrHeap heap = runtime.GetHeap();

    foreach (ClrRoot root in heap.EnumerateRoots())
    {
        if (root.Object == 0x0000000002f2ab20)
        {
            Console.WriteLine(root.Kind);
            if (root.Kind == GCRootKind.StaticVar)
                Console.WriteLine(root.Name);
        }
    }

您可以在DotNet blog

上阅读有关ClrMD库的更多信息

答案 1 :(得分:1)

我运行blog上发布的代码。

版本: Win7 X64 .NET 4

DOMAIN(000000000007E9D0):HANDLE(Pinned):1a17f8:Root:  0000000012381018(System.Object[])->
  0000000002391dc0(System.Collections.ArrayList)->
  0000000002391e78(System.Object[])->
  0000000002391e60(StaticRootedWhere.Fruit)



0:000> s-d 0000000012381018 L?0x2000 0000000002391dc0
00000000`12382fd8  02391dc0 00000000 0238fb30 00000000  ..9.....0.8.....


0:000> s-d 0 L?0xffffffffffffffff 00000000`12382fd8
00000000`00319680  12382fd8 00000000 02009443 00000000  ./8.....C.......
000007ff`000337d8  12382fd8 00000000 00000001 00000000  ./8.............
000007ff`00150160  12382fd8 00000000 24548b48 278ee828  ./8.....H.T$(..'




0:000> !u 000007ff`00150160
Normal JIT generated code
StaticRootedWhere.Program..cctor()
Begin 000007ff00150120, size 59

E:\..........\StaticRootedWhere\Program.cs @ 11:
000007ff`00150120 4883ec38        sub     rsp,38h
000007ff`00150124 48b8f0340300ff070000 mov rax,7FF000334F0h
000007ff`0015012e 8b00            mov     eax,dword ptr [rax]
000007ff`00150130 85c0            test    eax,eax
000007ff`00150132 7405            je      StaticRootedWhere!StaticRootedWhere.Program..cctor()+0x19 (000007ff`00150139)
000007ff`00150134 e817ac51ee      call    clr!JIT_DbgIsJustMyCode (000007fe`ee66ad50)
000007ff`00150139 488d0d58ff07ec  lea     rcx,[mscorlib_ni+0x4d0098 (000007fe`ec1d0098)]
000007ff`00150140 e81b2d0bee      call    clr!JIT_TrialAllocSFastMP_InlineGetThread (000007fe`ee202e60)
000007ff`00150145 4889442420      mov     qword ptr [rsp+20h],rax
000007ff`0015014a 488b442420      mov     rax,qword ptr [rsp+20h]
000007ff`0015014f 4889442428      mov     qword ptr [rsp+28h],rax
000007ff`00150154 488b4c2428      mov     rcx,qword ptr [rsp+28h]
000007ff`00150159 e802b7f5eb      call    mscorlib_ni!System.Collections.ArrayList..ctor() (000007fe`ec0ab860)
000007ff`0015015e 48b9d82f381200000000 mov rcx,12382FD8h
000007ff`00150168 488b542428      mov     rdx,qword ptr [rsp+28h]
000007ff`0015016d e88e270bee      call    clr!JIT_WriteBarrier_Fast (000007fe`ee202900)
000007ff`00150172 eb00            jmp     StaticRootedWhere!StaticRootedWhere.Program..cctor()+0x54 (000007ff`00150174)
000007ff`00150174 4883c438        add     rsp,38h
000007ff`00150178 c3              ret

我在此发布结果仅供您参考。这是我第二次在阅读博客后验证结果。第一次验证没有得到预期的结果。

答案 2 :(得分:0)

描述了in this blog的一种方法。对该方法的简短说明是,您希望找到一个将新元素添加到对象数组中的代码。该对象数组是静态字段数组(在您的情况下为00000000123c5018)。该方法的名称应该是AnOffendingType..ctor(),它是您正在寻找的静态类型构造函数。