7,8 МБ ключів, які я виділив лише для того, щоб їх викинути

Профайлер виявив приховані витрати у моєму коді.

Мій обробник запитів зчитує токени з величезного рядка та підсумовує їхню вагу. Логіка працювала, але пам'ять — ні.

Всередині «гарячого» циклу я виділяв 7,8 МБ рядків — по одному новому ключу для кожного пошуку в словнику — а потім одразу їх викидав.

Винуватцем був Substring. Кожен зріз створював новий об'єкт рядка.

200 000 токенів

  • Метод А (Substring): 23,4 мс, виділено 7 812 КБ.
  • Метод Б (Span Lookup): 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