我有一些非常大的托管进程的内存转储,我试图从中获取大量统计信息,并且能够呈现堆上相当深的对象图的交互式视图。!do <address>想一想与在带有 SOS 的 WinDbg 中设置类似的东西prefer_dml 1,您可以在其中不断单击属性并查看它们的值,只是在一个更友好的 UI 中比较许多对象。
我发现Microsoft.Diagnostics.Runtime (ClrMD) 特别适合这项任务,但我很难处理数组字段,而且我对对象字段有点困惑,我已经做了一些工作更好的。
数组:如果我将一个地址直接从堆中取出的数组作为目标并使用ClrType.GetArrayLength并且ClrType.GetArrayElementValue一切正常,但是一旦我挖掘另一个对象上的字段,我不确定我从ClrInstanceField.GetValue什么时候得到什么值ClrInstanceField.ElementType是ClrElementType.SZArray(我还没有Array在我的对象图中遇到过挖掘,但我也想处理它)。
编辑:我刚刚决定使用ClrTypeforSystem.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.GetTypeByNameor ClrHeap.GetObjectType。之后它完全依赖于ClrType.Fields和ClrInstanceField成员Type, ElementType, 和GetFieldValue
作为额外的奖励,我确实找到了随 NuGet 包提供的 XML Docs 的浏览器友好版本,尽管它与 IntelliSense 提供的文档相同。