codefest 2013. Скрыган К. — Оптимизация .net приложений на...
TRANSCRIPT
Как мы оптимизировали ReSharper
Скрыган Кирилл,JetBrains
DotTrace
Алгоритмическая производительность• DotTrace – как инструмент анализа
производительности• Sampling: почти «честное» время выполнения,
профилирование практически не накладное по производительности
Алгоритмическая производительность• Tracing: дорогое профилирование, не отражает
реального времени выполнения, но показывает количество вызов
• Timeline: инструмент для анализа производительности многопоточных приложений
Типичные продолбы
• Алгоритмический «взрыв» (квадрат или больше)• Ожидание на lock’ах• Memory traffic (о нём поподробнее )
Memory traffic: GC
• В деталях, механику CLR GC не знает никто, кроме самих CLR team. Алгоритмы и принципы CLR GC весьма закрыты.
Memory traffic: GC
• «Stop-the-world» - блокировка всех трэдов• Чем больше memory traffic – тем чаще вызывается
GC• LOH – Large Object Heap (>82 Кб) – специальная
куча для больших объектов
Memory traffic
• Стараемся не создавать новых объектов, там, где не нужно.
• Объекты зачастую неожиданно создаются в неочевидных местах.
Замыкания: то, что видим мы
Замыкания: что генерируется
Params: что мы видим
Params всегда аллоцирует объект!
Две лямбды…
…и только один замыкающий класс!
Yield
Во что компилируется yield
Closure scope
Ну и самое «сладкое»: IList vs List
List vs IList – думаете IList всегда лучше? IList
List
Memory traffic: прочие примеры
• LinQ, Select and others• Guid.ToString() создаёт дважды. Можно переписать
через stackalloc
ReSharper: статический анализ
Соображения о структурах данных
• Equals вызывается чаще чем GetEntry? – см. коллизии
• Интернирующие структуры данных• StringSlice – лекарство против SubString
StringSlice в лексере
INTERN
Неочевидные соображения о структурах данных : LocalList
LOH
• Объекты в LOH никогда не перемещаются• LOH только растет и никогда не уменьшается (т.е.
если объект собран сборщиком мусора, размер LOH все равно остается неизменным)
• Хип LOH освобождается только тогда, когда LOH полностью пуст
• Как следствие – OutOfMemory из-за сильно фрагментированной памяти
Пример: ChunkList
Boxing
• Очевидные проблемы: используем value types в качестве reference types
• public struct ToBeBoxed : IMySuperInterface {…}• Не забываем что все итераторы – struct’ы!
.NET method group bug
Delegate target Method group Lambda expression Ratio
Class 329 463 0.71
Interface 24474 461 53.1
Struct 28372 400 71.0
Более общие соображения
• «Кризис среднего возраста» для объектов• Есть смысл задумать о том, в каком поколении
собираются объекты. Желательно, чтобы в Gen0 • WeakReferences – только в крайнем случае.
Caches: тонкости
• LevelDb – храним кэши на диске• DirectMappedCache, LRUWeakReferenceCache –
«вытесняющие» словари с ограниченным размером
UI Thread: тонкости в обращении
• Chunked operations – прерываем операции в других потоках, чтобы не зависать в UI потоке
• InterruptableReadactivityCookie – операция, прерываемая в том числе по WriteLock.Acquire() из UI потока
Tools
• ReSharper – статический анализ кода на performance issues.
• DotTrace – профилятор• DotMemory, .NET Memory Profiler – memory-
профилятор• DotPeek (ReSharper) – декомпилятор• Ildasm.exe