7,8 МБ ключів, які я виділив лише для того, щоб їх викинути
Профайлер виявив приховані витрати у моєму коді.
Мій обробник запитів зчитує токени з величезного рядка та підсумовує їхню вагу. Логіка працювала, але пам'ять — ні.
Всередині «гарячого» циклу я виділяв 7,8 МБ рядків — по одному новому ключу для кожного пошуку в словнику — а потім одразу їх викидав.
Винуватцем був Substring. Кожен зріз створював новий об'єкт рядка.
200 000 токенів
- Метод А (
Substring): 23,4 мс, виділено 7 812 КБ. - Метод Б (
SpanLookup): 14,9 мс, виділено 0 КБ.
Метод Б працює в 1,5 раза швидше і не створює сміття.
У .NET 9 ви можете викликати GetAlternateLookup. Замість нового рядка ви передаєте ReadOnlySpan<char>, який є лише «вікном» у оригінальний рядок — без копіювання.
Словник хешує span безпосередньо порівняно з існуючими ключами, забезпечуючи той самий результат без виділення пам'яті.
Що варто пам'ятати
- Працює з
StringComparer.OrdinalтаStringComparer.OrdinalIgnoreCase. - Викликає помилку під час виконання, якщо ви використовуєте власний компаратор, який не підтримує альтернативний пошук.
- Ідеально підходить для «гарячих» шляхів, таких як парсери, обробники логів або сканери CSV.
- Не використовуйте це для простих пошуків із невеликою кількістю ключів.
Тепер я шукаю у своєму коді комбінацію Substring, після якої йде TryGetValue. Такий патерн марнує величезну кількість пам'яті.
Source: https://dev.to/ssukhpinder/78-mb-of-keys-i-allocated-just-to-throw-away-50mn
Optional learning community: https://github.com/ssukhpinder/dev-to-code-samples/tree/main/023-dictionary-alternate-lookup
