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,
stackalloc
puΓ² essere utilizzato per creare lβarray sullo stack, migliorando le prestazioni. - InteroperabilitΓ con codice non gestito:
stackalloc
puΓ² 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:
stackalloc
puΓ² essere utile per creare strutture dati temporanee per eseguire unβoperazione specifica, senza dover allocare memoria sullβheap. - Buffer per I/O:
stackalloc
puΓ² 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,
stackalloc
puΓ² essere utilizzato per allocare un buffer temporaneo sullo stack per memorizzare lβhash calcolato. - Codifica e decodifica:
stackalloc
puΓ² 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,
stackalloc
puΓ² essere utilizzato per allocare buffer temporanei per gestire i dati compressi/decompressi. - Crittografia:
stackalloc
puΓ² 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,
stackalloc
puΓ² 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,
stackalloc
puΓ² 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 utilizzarestackalloc
solo per blocchi di memoria di dimensioni ridotte e per brevi periodi. - CompatibilitΓ solo con tipi di valore senza riferimenti:
stackalloc
puΓ² essere utilizzato solo con tipi di valore che non contengono riferimenti, come i tipi primitivi (ad es.int
,float
,double
, ecc.) e lestruct
che contengono solo tipi di valore. Se si tenta di utilizzarestackalloc
con un tipo di valore che contiene riferimenti, verrΓ generato un errore di compilazione. - Vita breve degli oggetti allocati: Gli oggetti allocati con
stackalloc
hanno 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;
}