我正在使用CLR内存诊断库来获取正在运行的进程中所有线程的堆栈跟踪:
var result = new Dictionary<int, string[]>();
var pid = Process.GetCurrentProcess().Id;
using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
{
string dacLocation = dataTarget.ClrVersions[0].TryGetDacLocation();
var runtime = dataTarget.CreateRuntime(dacLocation); //throws exception
foreach (var t in runtime.Threads)
{
result.Add(
t.ManagedThreadId,
t.StackTrace.Select(f =>
{
if (f.Method != null)
{
return f.Method.Type.Name + "." + f.Method.Name;
}
return null;
}).ToArray()
);
}
}
Run Code Online (Sandbox Code Playgroud)
我从这里得到这个代码,它似乎适用于其他人,但它在指定的行上抛出了一个异常,带有消息This runtime is not initialized and contains no data.
dacLocation
被设为 C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll
标题非常明确:是否有相当于Mono的CLRMD,或者至少以任何方式非侵入性地读取外部Mono进程的堆以获取所有已分配对象的列表并读取其字段?
如果没有这样的工具,是否有一个API和一个关于Mono进程堆结构的文档,这将允许我为此目的实现我自己的策略?
我有一个托管进程的一些非常大的内存转储,我试图从中获取大量统计信息,并且能够呈现堆上相当深的对象图的交互式视图。想想!do <address>
与prefer_dml 1
在WinDbg中设置与SOS,在那里你可以不断地点击属性,并查看它们的值,只有在比较多的对象更友好的用户界面。
我发现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
具有Type
的ClrElementType.Object
我得到更好的结果,但仍需要更多一点。首先,在调用后GetFieldValue
我得到一个ulong
地址(?),我可以ClrInstanceField.Type.Fields
很好地使用它,所以我可以看到嵌套对象的字段名称和值。也就是说,我必须考虑多态性,所以我尝试ClrHeap.GetObjectType
在同一个地址上使用,它要么返回 NULL,要么返回完全不正确的东西。地址在我的第一个用例中有效,但在第二个用例中无效,这似乎很奇怪。
字符串:已修复(已找到解决方法)
因为我的真实项目已经使用带 SOS 的 DbgEng,我有一种不同的方法可以通过地址轻松获取字符串的值,但是尝试使用ClrInstanceField.GetFieldValue
成功返回字符串似乎很奇怪,但是使用完全不准确的结果(一堆奇怪的字符)。也许我做错了? …
我正在尝试将进程中的 ClrMD 附加到自身:
private static void Main()
{
var pid = Process.GetCurrentProcess().Id;
WriteLine($"PID: {pid}");
using (var dataTarget = DataTarget.AttachToProcess(pid, 1000))
{
WriteLine($"ClrMD attached");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我收到以下异常:
PID: 7416
Unhandled Exception: Microsoft.Diagnostics.Runtime.ClrDiagnosticsException: Could not attach to pid 1CF8, HRESULT: 0x80070057
at Microsoft.Diagnostics.Runtime.DbgEngDataReader..ctor(Int32 pid, AttachFlag flags, UInt32 msecTimeout)
at Microsoft.Diagnostics.Runtime.DataTarget.AttachToProcess(Int32 pid, UInt32 msecTimeout, AttachFlag attachFlag)
at Microsoft.Diagnostics.Runtime.DataTarget.AttachToProcess(Int32 pid, UInt32 msecTimeout)
at BanksySan.Scratch.Console.Program.Main(String[] args)
Run Code Online (Sandbox Code Playgroud)
我可以在被动模式下连接,但不能在入侵或非入侵模式下连接。
我正在调查生产中的内存泄漏问题并检索内存转储.我试图抛弃累积物体的值,我遇到了WeakReference
.这是我在WinDBG中得到的:
0:000> !do 000000011a306510
Name: System.WeakReference
MethodTable: 000007feeb3f9230
EEClass: 000007feeadda218
Size: 24(0x18) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
MT Field Offset Type VT Attr Value Name
000007feeb3f4a00 400068d 8 System.IntPtr 1 instance 343620e0 m_handle
0:000> !do 343620e0
<Note: this object has an invalid CLASS field>
Invalid object
Run Code Online (Sandbox Code Playgroud)
我们可以发现我们不能将该m_handle
值用作对象地址.我检查了代码,WeakReference
它是完全extern
代码.
我的问题是,我们如何使用WinDBG/SOS检查它的价值?另外,我正在为ClrMD的问题编写ad-hoc分析器,那么我应该如何检查对象的对象引用WeakReference
呢?