Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Заглянуть «под капот» кода или посмотреть на внутреннее устройство 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