Как снизить аллокации в горячем коде
Вопрос
Как вы снижаете нагрузку на GC в горячем пути сервиса?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Сначала измерить: BenchmarkDotNet с MemoryDiagnoser, dotnet-counters, профилировщик
Span и stackalloc для временных буферов, парсинг без Substring
ArrayPool и ObjectPool для переиспользования
Структуры вместо классов для мелких значений, без упаковки
Избегать LINQ и замыканий в самых горячих циклах
Ёмкость коллекций и StringBuilder заранее
Что могут спросить следом
- Когда stackalloc опасен?
- Чем плох большой Gen2 и как его заметить в метриках?
Разбор
Начинаю с измерений: BenchmarkDotNet с MemoryDiagnoser показывает байты на операцию, а dotnet-counters в проде частоту сборок и размер поколений. Оптимизирую только то, что реально горячее.
Дальше типичные приёмы. Временные буферы через Span<T>: небольшие на стеке через stackalloc, большие из ArrayPool<T>.Shared с обязательным Return. Парсинг через ReadOnlySpan<char> вместо Substring и Split. Для дорогих объектов ObjectPool<T>, например для StringBuilder.
Мелкие значения делаю readonly struct и слежу, чтобы они не упаковывались через интерфейсы. В самых горячих циклах убираю LINQ и лямбды с захватом. Коллекциям и StringBuilder задаю ёмкость заранее, чтобы не было переаллокаций. И отдельно слежу за LOH: большие временные массивы, например при чтении тел запросов, это прямой путь к полным сборкам.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.