我有一些非常大的托管进程的内存转储,我试图从中获取大量统计信息,并且能够呈现堆上相当深的对象图的交互式视图。!do <address>
想一想与在带有 SOS 的 WinDbg 中设置类似的东西prefer_dml 1
,您可以在其中不断单击属性并查看它们的值,只是在一个更友好的 UI 中比较许多对象。
我发现Microsoft.Diagnostics.Runtime (ClrMD) 特别适合这项任务,但我很难处理数组字段,而且我对对象字段有点困惑,我已经做了一些工作更好的。
数组:如果我将一个地址直接从堆中取出的数组作为目标并使用ClrType.GetArrayLength
并且ClrType.GetArrayElementValue
一切正常,但是一旦我挖掘另一个对象上的字段,我不确定我从ClrInstanceField.GetValue
什么时候得到什么值ClrInstanceField.ElementType
是ClrElementType.SZArray
(我还没有Array
在我的对象图中遇到过挖掘,但我也想处理它)。
编辑:我刚刚决定使用ClrType
forSystem.UInt64
来取消引用数组字段(parent address + offset of the array field
用于计算存储数组指针的地址),然后我可以像从 EnumerateObjects 获得它一样使用它。我现在对一些不支持该ArrayComponentType
属性的数组有一些困难。我还没有使用结构数组进行测试,所以我也想知道这是否是内联结构的 C 风格分配,就像它一样,int[]
或者它是否是指向堆上结构的指针数组。Guid[]
是我遇到问题的类型之一ArrayComponentType
。
对象:已修复(逻辑错误)
使用ClrInstanceField
具有 aType
的aClrElementType.Object
我会得到更好的结果,但仍需要更多。首先,在调用后GetFieldValue
我得到一个ulong
地址(?),我可以ClrInstanceField.Type.Fields
很好地使用它,所以我可以看到嵌套对象的字段名称和值。也就是说,我必须考虑多态性,所以我尝试ClrHeap.GetObjectType
在同一个地址上使用它,它要么返回 NULL,要么返回完全不正确的东西。该地址在我的第一个用例中有效,但在第二个用例中无效,这似乎很奇怪。
字符串:已修复(找到解决方法)
因为我的实际项目已经使用带 SOS 的 DbgEng,所以我有一种不同的方法可以通过地址轻松获取字符串的值,但是尝试使用ClrInstanceField.GetFieldValue
成功返回字符串似乎很奇怪,但是完全不准确的结果(一堆奇怪的字符)。也许我做错了?
编辑:我已经从我的原始代码中提取了现在在 LINQPad 中运行的抽象。在这里发帖有点长,但这里都是要点。所有的复制/粘贴/重构仍然有点混乱,我将进一步清理它,可能在解决这些问题后在 CodePlex 或 GitHub 上发布最终源代码。
代码库相当大且特定于项目,但如果绝对有必要,我可以提取一个样本集。也就是说,对 ClrMD 对象的所有访问都相当简单。我从 SOS 命令中获取初始地址,例如!dumpheap -stat
(对根对象工作正常),然后我使用ClrHeap.GetTypeByName
or ClrHeap.GetObjectType
。之后它完全依赖于ClrType.Fields
和ClrInstanceField
成员Type
, ElementType
, 和GetFieldValue
作为额外的奖励,我确实找到了随 NuGet 包提供的 XML Docs 的浏览器友好版本,尽管它与 IntelliSense 提供的文档相同。