ClrMd выдает исключение при создании среды выполнения

Я использую библиотеку диагностики памяти 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()
                );
            }
        }

Я получил этот код отсюда, и он, кажется, работает для других, но он выдает исключение для меня в указанной строке с сообщением This runtime is not initialized and contains no data.

dacLocation устанавливается как C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll

2 ответа

Решение

ClrMD в настоящее время не поддерживает.NET 4.6. На GitHub есть открытый запрос, который решает эту проблему всего одной строкой. Конечно, вы можете клонировать проект и создать свой собственный ClrMD, который не имеет этой проблемы.

Или я могу поделиться временным взломом, который я использовал в течение последних нескольких недель:

public static ClrRuntime CreateRuntimeHack(this DataTarget target, string dacLocation, int major, int minor)
{
    string dacFileNoExt = Path.GetFileNameWithoutExtension(dacLocation);
    if (dacFileNoExt.Contains("mscordacwks") && major == 4 && minor >= 5)
    {
        Type dacLibraryType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.DacLibrary");
        object dacLibrary = Activator.CreateInstance(dacLibraryType, target, dacLocation);
        Type v45RuntimeType = typeof(DataTarget).Assembly.GetType("Microsoft.Diagnostics.Runtime.Desktop.V45Runtime");
        object runtime = Activator.CreateInstance(v45RuntimeType, target, dacLibrary);
        return (ClrRuntime)runtime;
    }
    else
    {
        return target.CreateRuntime(dacLocation);
    }
}

Я знаю, это ужасно и зависит от Reflection. Но, по крайней мере, пока это работает, и вам не нужно менять код.

Вы можете решить эту проблему, загрузив последнюю версию Microsoft.Diagnostics.Runtime.dll (v0.8.31-бета): https://www.nuget.org/packages/Microsoft.Diagnostics.Runtime

Версия v0.8.31-бета отмечена рядом устаревших функций, так как, как упоминал Алоис Краус, runtime.GetHeap() может сломаться. Я смог решить эту проблему, создав мою среду выполнения следующим образом:

DataTarget target = DataTarget.AttachProcess(pid, timeout, mode);
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
ClrHeap heap = runtime.GetHeap();

Вся чушь с TryGetDacLocation() сейчас ненужно.

Другие вопросы по тегам