7,8 MB an Schlüsseln, die ich nur zum Wegwerfen alloziert habe
Ein Profiler hat einen versteckten Kostenfaktor in meinem Code aufgedeckt.
Mein Request-Handler liest Token aus einem riesigen String und summiert deren Gewichtungen. Die Logik funktionierte, aber der Speicher nicht.
Innerhalb einer Hot Loop habe ich 7,8 MB an Strings alloziert – einen neuen Schlüssel für jeden Dictionary-Lookup – und den Schlüssel dann sofort wieder weggeworfen.
Der Übeltäter war Substring. Jedes Slice erzeugte ein neues String-Objekt.
200.000 Token
- Methode A (Substring): 23,4 ms, 7.812 KB alloziert.
- Methode B (Span Lookup): 14,9 ms, 0 KB alloziert.
Methode B ist 1,5-mal schneller und erzeugt keinen Garbage.
In .NET 9 können Sie GetAlternateLookup aufrufen. Anstatt eines neuen Strings übergeben Sie einen ReadOnlySpan<char>, der lediglich ein Fenster auf den ursprünglichen String ist – ohne Kopieren.
Das Dictionary hasht den Span direkt gegen die vorhandenen Schlüssel und liefert dasselbe Ergebnis ohne die Allokation.
Was man beachten sollte
- Funktioniert mit
StringComparer.OrdinalundStringComparer.OrdinalIgnoreCase. - Wirft zur Laufzeit eine Exception, wenn Sie einen benutzerdefinierten Comparer verwenden, der keine Unterstützung für Alternate Lookup bietet.
- Ideal für Hot Paths wie Parser, Log-Prozessoren oder CSV-Scanner.
- Lassen Sie es bei einfachen Lookups mit nur wenigen Schlüsseln weg.
Ich suche jetzt in meinem Code gezielt nach Substring, gefolgt von TryGetValue. Dieses Muster verschwendet massive Mengen an Speicher.
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
