7,8 MB de claves que asigné solo para desechar
Un profiler reveló un coste oculto en mi código.
Mi manejador de peticiones lee tokens de una cadena enorme y suma sus pesos. La lógica funcionaba, pero la memoria no.
Dentro de un bucle crítico, asigné 7,8 MB de cadenas —una clave nueva para cada búsqueda en el diccionario— y luego deseché la clave inmediatamente.
El culpable era Substring. Cada fragmento creaba un nuevo objeto de cadena.
200.000 tokens
- Método A (Substring): 23,4 ms, 7.812 KB asignados.
- Método B (Span Lookup): 14,9 ms, 0 KB asignados.
El método B es 1,5 veces más rápido y no genera basura.
En .NET 9 puedes llamar a GetAlternateLookup. En lugar de una nueva cadena, pasas un ReadOnlySpan<char>, que es simplemente una ventana a la cadena original, sin copias.
El diccionario calcula el hash del span directamente contra las claves existentes, ofreciendo el mismo resultado sin la asignación de memoria.
Cosas a tener en cuenta
- Funciona con
StringComparer.OrdinalyStringComparer.OrdinalIgnoreCase. - Lanza una excepción en tiempo de ejecución si utilizas un comparador personalizado que carezca de soporte para búsquedas alternativas.
- Ideal para rutas críticas (hot paths) como analizadores (parsers), procesadores de logs o escáneres de CSV.
- No lo uses para búsquedas sencillas con solo unas pocas claves.
Ahora busco en mi código el patrón Substring seguido de TryGetValue. Ese patrón desperdicia cantidades masivas de memoria.
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
