我正在对内存泄漏进行故障排除,发现一个对象被保存在内存中,因为它被字典引用。当我在字典实例上执行!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相关的方法。
如果没有这些信息,我怎样才能找出哪个对象包含静态字典?
答案 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(),它是您正在寻找的静态类型构造函数。