În dezvoltarea aplicațiilor web de înaltă frecvență sau a sistemelor de tranzacționare în timp real, cel mai mare inamic al latenței predictibile este Garbage Collector-ul. Fiecare alocare inutilă pe Heap (cum ar fi apelurile string.Substring(), string.Split() sau crearea de vectori temporari byte[]) forțează colectorul să declanșeze cicluri frecvente de curățare în Generația 0 și Generația 1.
Ecosistemul modern .NET pune la dispoziție o suită completă de instrumente pentru scrierea de cod Zero-Allocation, permițând parsarea și manipularea fluxurilor de date la viteza memoriei native.
| Caracteristică | Span<T> / ReadOnlySpan<T> |
Memory<T> / ReadOnlyMemory<T> |
|---|---|---|
| Natură Tip | ref struct (alocat exclusiv pe stivă). |
struct normal (poate fi stocat pe Heap). |
| Compatibilitate async/await | NU poate fi utilizat peste puncte de suspensie await. |
DA, poate fi transmis și păstrat în metode asincrone. |
| Scenariu Optim | Bucle rapide de parsare sincronă, algoritmi de criptografie, tăiere de text. | Operațiuni I/O asincrone pe socket-uri sau fișiere (Stream.ReadAsync). |
using System.Buffers;
public async Task ProceseazaFisierMareAsync(Stream streamIntrare)
{
// În loc de 'new byte[65536]' la fiecare cerere (care ar polua Gen 0 sau LOH):
// Împrumutăm un buffer pre-alocat direct din pool-ul comun partajat:
byte[] buffer = ArrayPool<byte>.Shared.Rent(65536);
try
{
int octetiCititi;
while ((octetiCititi = await streamIntrare.ReadAsync(buffer.AsMemory(0, buffer.Length))) > 0)
{
// Procesăm felia de date fără alocare nouă:
ProceseazaChunk(buffer.AsSpan(0, octetiCititi));
}
}
finally
{
// Returnăm obligatoriu buffer-ul în pool pentru a fi reutilizat de alte cereri:
ArrayPool<byte>.Shared.Return(buffer, clearArray: false);
}
}
private void ProceseazaChunk(ReadOnlySpan<byte> date)
{
// Operațiuni de verificare și parsare pe stivă
}
Alocare pe Stivă cu stackalloc
Pentru buffere mici cunoscute (sub 1-2 KB), directiva stackalloc alocă memoria direct pe cadrul de stivă al metodei curente, fiind dealocată automat la ieșirea din scope cu cost zero:
Span<byte> hashBuffer = stackalloc byte[32]; // Alocare pe stivă, zero Heap GC!
GenerareSha256(dateIntrare, hashBuffer);