Заглянуть «под капот» кода или посмотреть на внутреннее устройство CLR можно с помощью множества инструментов. Этот пост родился из твита, и я должен поблагодарить всех, кто помог составить список подходящих инструментов. Если я пропустил какие-то из них, напишите в комментариях.
Во-первых, я должен упомянуть, что хороший отладчик уже присутствует в Visual Studio и VSCode. Также существует множество хороших (коммерческих) профилировщиков .NET и инструментов мониторинга приложений, на которые стоит взглянуть. Например, недавно я попробовал поработать с Codetrack и был впечатлён его возможностями.
Однако оставшийся пост посвящён инструментам для выполнения отдельных задач, которые позволят лучше понять, что происходит. Все инструменты имеют открытый исходный код.
PerfView от Вэнса Моррисона
PerfView – великолепный инструмент, который я использую уже несколько лет. Он работает на основе трассировки событий Windows (ETW) и позволяет лучше понять, что происходит внутри CLR, а также даёт возможность получить профиль использования памяти и центрального процессора. Чтобы освоить инструмент, придётся впитать много информации, например с помощью обучающих видео, но это стоит потраченного времени и усилий.
Инструмент настолько полезен, что сами инженеры Microsoft используют его, а многие из недавних улучшений производительности в MSBuild появились после анализа узких мест с помощью PerfView.
Инструмент создан на базе библиотеки Microsoft.Diagnostics.Tracing.TraceEvent library, которую можно использовать для создания собственных инструментов. Кроме того, поскольку исходный код библиотеки является открытым, в ней благодаря сообществу появилось множество полезных функций, например графики flame-graphs:
SharpLab от Андрея Щёкина
SharpLab появился как инструмент для проверки IL-кода, генерируемого компилятором Roslyn, и со временем превратился в нечто большее:
SharpLab – интерактивная среда для запуска кода .NET, в которой отображаются промежуточные шаги и результаты компиляции кода. Некоторые функции языка – всего лишь обёртки для других, например using() становится try/catch. С помощью SharpLab вы увидите код, как его видит компилятор и лучше поймёте суть языков .NET.
Инструмент поддерживает C#, Visual Basic и F#, но самыми интересными функциями в нём являются Decompilation/Disassembly:
Функции декомпиляции/дизассемблирования можно использовать для:
- C#
- Visual Basic
- IL
- JIT Asm (нативный Asm Code)
Вы правильно поняли: инструмент выводит код ассемблера, который .NET JIT генерирует из вашего кода C#:
Object Layout Inspector от Сергея Теплякова
С помощью этого инструмента вы сможете проанализировать структуру .NET объектов в памяти, т.е. как JITter расположил поля, принадлежащие вашему классу или структуре. Это полезно при написании высокопроизводительного кода. Кроме того, приятно иметь инструмент, который сделает сложную работу за нас.
Официальной документации, которая бы описывала структуру полей, не существует, поскольку авторы CLR оставили за собой право изменить её в будущем. Но знания о структуре могут быть полезны, если вы работаете над быстродействующим приложением.
Как можно изучить структуру? Можно посмотреть на необработанную память в Visual Studio или использовать команду !dumpobj
в SOS Debugging Extension. Оба подхода требуют много усилий, поэтому мы создадим инструмент, который будет выводить структуру объекта во время выполнения.
Согласно примеру в репозитории GitHub, если вы используете TypeLayout.Print<NotAlignedStruct>()
с подобным кодом:
public struct NotAlignedStruct
{
public byte m_byte1;
public int m_int;
public byte m_byte2;
public short m_short;
}
появится следующий вывод, который точно покажет, как CLR расположит struct в памяти на основании правил оптимизации и заполнения байтами.
Size: 12. Paddings: 4 (%33 of empty space)
|================================|
| 0: Byte m_byte1 (1 byte) |
|--------------------------------|
| 1-3: padding (3 bytes) |
|--------------------------------|
| 4-7: Int32 m_int (4 bytes) |
|--------------------------------|
| 8: Byte m_byte2 (1 byte) |
|--------------------------------|
| 9: padding (1 byte) |
|--------------------------------|
| 10-11: Int16 m_short (2 bytes) |
|================================|
The Ultimate .NET Experiment (TUNE) от Конрада Кокосы
Как сказано на странице GitHub, TUNE – многообещающий инструмент. Он поможет изучить внутреннее устройство .NET и способы повышения производительности с помощью экспериментов с кодом C#.
Подробную информацию о нём можно узнать из этого поста, но на высоком уровне он функционирует следующим образом:
- напишите работающий пример кода на C#, который содержит хотя бы один класс с публичным методом, принимающим один строковый параметр. Код запускается с помощью кнопки Run. Вы можете включить любое количество методов и классов. Но помните, что первый публичный метод из первого публичного класса будет выполнен с использованием первого параметра из окна ввода под кодом;
- нажмите кнопку Run, чтобы скомпилировать и выполнить код. Кроме того, он будет компилирован в IL-код и код ассемблера в соответствующих вкладках;
- пока Tune работает (в том числе во время выполнения кода), инструмент строит график, отображающий данные сборщика мусора. Он содержит информацию о размерах поколений и сеансах сбора мусора (представлены в виде вертикальных линий с числом внизу, которое указывает на то, в каком поколении выполняется сборка мусора).
Выглядит это следующим образом:
Инструменты на базе CLR Memory Diagnostics (ClrMD)
Наконец, давайте взглянем на определённую категорию инструментов. С момента выхода .NET разработчики всегда могли использовать WinDBG и SOS Debugging Extension, чтобы посмотреть, что происходит в среде выполнения .NET. Однако, это не самые простые инструменты для первого знакомства и, как сказано в следующем твите, не всегда самые продуктивные:
К счастью, Microsoft сделал доступной библиотеку ClrMD (также известную, как Microsoft.Diagnostics.Runtime), и теперь любой может создать инструмент для анализа дампов памяти программ .NET. Подробную информацию можно прочитать в официальном блоге. Я также рекомендую взглянуть на ClrMD.Extensions, которые “… обеспечивают интеграцию с LINPad и делают использование ClrMD ещё проще”.
Я хотел собрать список всех существующих инструментов и призвал на помощь твиттер. Напоминалочка самому себе: осторожнее с твитами. Менеджер, ответственный за WinDBG, может прочитать их и расстроиться!
Большинство этих инструментов работают на базе ClrMD, потому что так проще всего. Но при желании можно использовать COM-интерфейсы напрямую. Также нужно заметить, что любой инструмент на базе ClrMD не является кроссплатформенным, поскольку сама ClrMD предназначена только для Windows. Описание кроссплатформенных вариантов можно найти в Analyzing a .NET Core Core Dump on Linux.
Наконец, чтобы как-то соблюсти баланс, недавно появилась улучшенная версия WinDBG, которой сразу же попытались добавить функциональность:
- Extending the new WinDbg, Part 1 – Buttons and commands
- Extending the new WinDbg, Part 2 – Tool windows and command output
- Extending the new WinDbg, Part 3 – Embedding a C# interpreter
- WinDBG extension + UI tool extensions и ещё здесь
- NetExt – приложение WinDBG, которое облегчает отладку в .NET по сравнению с текущими опциями: sos или psscor. Также см. эту статью InfoQ.
После всех этих слов переходим к списку:
- SuperDump (GitHub)
- Средство для автоматического анализа аварийного дампа (презентация)
- msos (GitHub)
- Среда с интерфейсом командной строки типа WinDbg для выполнения SOS-команд при отсутствии SOS.
- MemoScope.Net (GitHub)
- Инструмент для анализа памяти процесса в .NET. Можно сделать дамп памяти приложения в файл и прочитать его позже.
- Файл содержит все данные (объекты) и информацию о тредах (состояние, стек, стек вызовов). MemoScope.Net проанализирует данные и поможет найти утечки памяти и взаимные блокировки.
- dnSpy (GitHub)
- Отладчик и редактор сборок .NET
- Его можно использовать для редактирования и отладки сборок, даже если у вас нет исходного кода.
- MemAnalyzer (GitHub)
- Инструмент анализа памяти для управляемого кода. Присутствует интерфейс командной строки.
- Подобно
!DumpHeap
в Windbg может определить, какие объекты занимают больше всего места в куче без необходимости устанавливать отладчик.
- DumpMiner (GitHub)
- Инструмент с графическим интерфейсом для работы с ClrMD. Больше возможностей появится в будущем.
- Trace CLI (GitHub)
- Инструмент для отладки и отслеживания во время эксплуатации
- Shed (GitHub)
- Shed – приложение, которое анализирует выполнение программы в .NET. Его можно использовать для анализа вредоносного ПО, чтобы получить данные о том, какая информация сохраняется, при запуске такого ПО. Shed может:
- извлекать все объекты, хранящиеся в управляемой куче;
- выводить строки, хранящиеся в памяти;
- создавать моментальный снимок кучи в формате JSON для последующей обработки;
- делать дамп всех модулей, загруженных в память.
Вы можете найти множество других инструментов, которые используют ClrMD. Сделать её доступной было хорошей идеей Microsoft.
Другие инструменты
Стоит упомянуть и другие инструменты:
- DebugDiag
- Инструмент DebugDiag создан для устранения таких проблем, как зависания, низкая производительность, утечки памяти или её фрагментация, а также отказы процессов, выполняющихся в пользовательском режиме (теперь с интеграцией CLRMD).
- SOSEX (возможно больше не разрабатывается)
- … расширение для отладки управляемого кода, которое снижает моё недовольство SOS.
- VMMap от Sysinternals
- VMMap – средство для анализа виртуальной и физической памяти процессов.
- Я применял его, чтобы проанализировать использование памяти в CLR
Комментарии (9)
Pavel7
19.08.2019 09:09+1В sysinternals есть еще procdump, который умеет на ходу цепляться к .net приложениям и дампить все exception-ы, включая обработанные. Бывает полезно для анализа исполнения корявого кода на проде, чтобы понять что там внутри происходит.
procdump -e 1 -f "" [PID]
Doverie
19.08.2019 16:36Спасибо за статью, давно такое ждал.
Давай пару гайдов для «зеленых» по маст хев утилиткам.
Exponent
19.08.2019 18:06Предлагаю добавить и ANTS Performance Profiler, много раз меня выручал. Пользовался и ANTS Memory Profiler, но он несколько неинтуитивен. Еще бы добавил .NET Reflector.
Ununtrium
20.08.2019 15:32Описание кроссплатформенных вариантов можно найти в Analyzing a .NET Core Core Dump on Linux
Есть мнение что статья 2017 года протухла, учитывая темпы развития .NET Core.
legigor
Интересно, что для .NET Core / Linux этот список превращается в тыкву.
sidristij Автор
Предлагаю не отчаиваться: ведь .NET Core только начал своё шествие. Всё будет в лучшем виде: я уверен )
legigor
«Начал», — это уже 3.0 на подходе и у нас 2 года хайлоада на проде :)
Но че-то не покидает ощущение, что windows из него еще очень долго вытравливать будут. Когда нужен не какой-то модный портированный тул из блога Хансельмана, а когда нативные инструменты будут в первую очередь появляться для линукса, как для продакшн-платформы, а оттуда адаптироваться на windows, а не наооборот. Это как и с WLS, когда любой шаг в сторону и абстракция разваливается и все время продираешься через какой-то ментальный импенданс. Плюс комьюнити, сами дотнет-разработчики ментально сильно сопротивляются unux-унификации. По наблюдениям, если alt.net еще многие пережили с энтузиазмом, то процесс un-windows вызывает у многих старичков сильные душевные страдания.
sidristij Автор
Ничего, попривыкают. Это всё лень и обида. Вроде как только что всё знал, был крутым, а сегодня всё помножили на 0.5 :) Подтянут все утилиты, я уверен