stackalloc Γ¨ una parola chiave in C# che permette di allocare un blocco di memoria sullo Stack, invece che sullβHeap. PoichΓ© la memoria allocata sullo stack viene automaticamente rilasciata quando il metodo corrente termina, lβutilizzo di stackalloc puΓ² ridurre la pressione sul garbage collector e migliorare le prestazioni dellβapplicazione.
Quando utilizzarlo
Lβutilizzo principale di stackalloc Γ¨ come alternativa all'allocazione di memoria sull'heap per gli array, specialmente per array di piccole dimensioni e quando si cerca di ottenere un miglioramento delle prestazioni.
Ecco 10 casi dβuso in cui stackalloc puΓ² essere utile:
- Allocazione di array temporanei: Se hai bisogno di un array temporaneo per eseguire unβoperazione specifica e la dimensione dellβarray Γ¨ piccola,
stackallocpuΓ² essere utilizzato per creare lβarray sullo stack, migliorando le prestazioni. - InteroperabilitΓ con codice non gestito:
stackallocpuΓ² essere utilizzato per allocare rapidamente memoria sullo stack quando si lavora con codice non gestito (ad esempio, chiamate a funzioni di librerie native), per passare dati tra codice gestito e non gestito. - Strutture dati temporanee:
stackallocpuΓ² essere utile per creare strutture dati temporanee per eseguire unβoperazione specifica, senza dover allocare memoria sullβheap. - Buffer per I/O:
stackallocpuΓ² essere utilizzato per creare rapidamente buffer temporanei per eseguire operazioni di input/output (ad esempio, leggere o scrivere dati da file o socket). - Calcolo di hash: Durante il calcolo di hash su una sequenza di dati,
stackallocpuΓ² essere utilizzato per allocare un buffer temporaneo sullo stack per memorizzare lβhash calcolato. - Codifica e decodifica:
stackallocpuΓ² essere utilizzato per allocare buffer temporanei per eseguire operazioni di codifica e decodifica (ad esempio, conversione tra codifiche di caratteri, codifica/decodifica base64, ecc.). - Compressione e decompressione: Quando si lavora con algoritmi di compressione o decompressione,
stackallocpuΓ² essere utilizzato per allocare buffer temporanei per gestire i dati compressi/decompressi. - Crittografia:
stackallocpuΓ² essere utilizzato per allocare buffer temporanei per eseguire operazioni di crittografia e decrittografia, ad esempio quando si lavora con algoritmi simmetrici o asimmetrici. - Elaborazione di immagini: Durante lβelaborazione di immagini,
stackallocpuΓ² essere utilizzato per allocare buffer temporanei per contenere i dati dellβimmagine o per eseguire operazioni come la convoluzione o il filtraggio. - Gestione delle matrici: Quando si lavora con matrici,
stackallocpuΓ² essere utilizzato per allocare matrici temporanee per operazioni come la trasposizione, la moltiplicazione o la decomposizione.
Come utilizzarlo
Quando si utilizza stackalloc, si alloca un blocco di memoria sullo stack che puΓ² essere utilizzato per memorizzare un insieme di elementi di tipo valore. Tuttavia, stackalloc restituisce un puntatore a tale blocco di memoria, che puΓ² comportare rischi in termini di sicurezza e stabilitΓ se non viene gestito correttamente.
Posso utilizzare la classe Span<T> (vedi Span e ReadOnlySpan; Span<T> Γ¨ un tipo di struttura che rappresenta una vista contigua di memoria di una collezione di elementi di tipo T) per creare una vista sicura e gestita del blocco di memoria allocato sullo stack.
Stackalloc puΓ² essere usato per inizializzare un oggetto Span<T> che rappresenta il blocco di memoria allocato.
// Utilizzo di stackalloc per allocare un blocco di memoria sullo stack
// In questo caso utilizzo Span<T> in quanto prevedo che tali debbano essere modificati
Span<int> data = stackalloc int[256];
// Se l'array Γ¨ in sola lettura posso usare ReadOnlySpan
ReadOnlySpan<int> data = stackalloc int[256];Limitazioni
Le limitazioni di stackalloc sono principalmente dovute alla natura dello stack e alle sue implicazioni per la gestione della memoria. Di seguito sono elencate alcune delle principali limitazioni associate allβuso di stackalloc in C#:
- Dimensione limitata dello stack: Lo stack ha generalmente una dimensione molto piΓΉ piccola rispetto allβheap. Di conseguenza, lβallocazione di grandi quantitΓ di memoria sullo stack puΓ² causare unβeccezione
StackOverflowException. Pertanto, Γ¨ importante utilizzarestackallocsolo per blocchi di memoria di dimensioni ridotte e per brevi periodi. - CompatibilitΓ solo con tipi di valore senza riferimenti:
stackallocpuΓ² essere utilizzato solo con tipi di valore che non contengono riferimenti, come i tipi primitivi (ad es.int,float,double, ecc.) e lestructche contengono solo tipi di valore. Se si tenta di utilizzarestackalloccon un tipo di valore che contiene riferimenti, verrΓ generato un errore di compilazione. - Vita breve degli oggetti allocati: Gli oggetti allocati con
stackallochanno una durata limitata al metodo corrente. Non Γ¨ possibile restituire un riferimento a un oggetto allocato sullo stack al chiamante del metodo, in quanto la memoria verrΓ automaticamente rilasciata alla fine del metodo. Per ovviare a questo problema, Γ¨ possibile utilizzareSpan<T>o copiare il contenuto dellβoggetto allocato sullo stack in un oggetto allocato sullβheap.
Esempio
Nellβesempio seguente, mettiamo a confronto due versioni di un metodo CalculateSumOfSquares che calcola la somma dei quadrati di un intervallo di numeri interi. Nel primo esempio, utilizziamo stackalloc per allocare lβarray temporaneo sullo stack. Nel secondo esempio, invece, allocchiamo lβarray sullβheap.
Esempio con stackalloc
public static long CalculateSumOfSquares(int start, int end)
{
int length = end - start + 1;
// Utilizzo di stackalloc per allocare un array temporaneo sullo stack
Span<int> squares = length <= 256 ? stackalloc int[length] : new int[length];
for (int i = start; i <= end; i++)
{
squares[i - start] = i * i;
}
long sum = 0;
for (int i = 0; i < length; i++)
{
sum += squares[i];
}
return sum;
}Esempio senza stackalloc
public static long CalculateSumOfSquares(int start, int end)
{
int length = end - start + 1;
// Allocazione di un array temporaneo sull'heap
int[] squares = new int[length];
for (int i = start; i <= end; i++)
{
squares[i - start] = i * i;
}
long sum = 0;
for (int i = 0; i < length; i++)
{
sum += squares[i];
}
return sum;
}