Introduction
Allocating some kind of a buffer (e.g. array) on a heap is a quite straightforward behaviour. It happens anytime we do something like this: var array = new int[5]
. It is perfectly normal to use it – it is well known and intuitive solution. However, we can also allocate such a buffer on the stack. On the one hand it entails some risks, but on the other it can safe some memory for us.
Stackalloc
Stackalloc is an expression that allocates a block of memory on the stack. Thanks to that we can allocate a buffer on the stack instead on the heap. To do that we can use Span struct: Span<int> span = stackalloc int[7];
. The syntactic seems to be pretty intuitive and understandable.
BE CAREFUL: As it stands in the documentation: “The amount of memory available on the stack is limited. If you allocate too much memory on the stack, a StackOverflowException is thrown”. It is also important to mention that the StackOverflowException is kind of exception that cannot be caught. In other words, StackOverflowException = application termination. It doesn’t mean that it shouldn’t be used at all. It does mean that it should be used with great care and awareness.
Example
Let’s consider the following StackallocExecutor
class:
public class StackallocExecutor
{
private readonly int _size;
private readonly Random _random;
public StackallocExecutor(int size)
{
_size = size;
_random = new Random();
}
public int Stackalloc()
{
Span<int> span = stackalloc int[_size];
for (int i = 0; i < span.Length; i++)
span[i] = _random.Next();
for (int i = 0; i < span.Length; i++)
if (i % 2 == 1)
span[i] += 1;
var max = span[0];
for (int i = 1; i < span.Length; i++)
if (span[i] > max)
max = span[i];
return max;
}
public int NoStackalloc()
{
var array = new int[_size];
for (int i = 0; i < array.Length; i++)
array[i] = _random.Next();
for (int i = 0; i < array.Length; i++)
if (i % 2 == 1)
array[i] += 1;
var max = array[0];
for (int i = 1; i < array.Length; i++)
if (array[i] > max)
max = array[i];
return max;
}
}
The class has two methods Stackalloc
and NoStackalloc
. Both of them do the the same – create a buffer, populate the buffer, add “1” to the odd indexes and return the max value. Maybe it is not the most real-world scenario but I hadn’t better idea at the time of writing the code😁.
Alright, but what’s the cool thing about the stackalloc at all? Let’s see the benchmark result!
Benchmark
This time the crucial part of the results is the last column, i.e. “Allocated”.
As you can see, no matter what the size of buffer is, the “Allocated” value for the Stackalloc
method is the same. NoStackalloc
method does quite the opposite, the greater size, the greater allocations.
Summary
To sum up, having an ability to allocate reasonably small buffer on the stack seems to be interesting and useful feature. However, the StackOverflowException is still there and might kill the application without hesitation.
As always I’ve prepared an example and you can find it on my github, project: stackalloc, benchmark project: stackalloc-benchmark.
I encourage you to go through the code, debug it and try to test your own scenarios e.g. killing an application with StackOverflowException (for me the following throws the exception):
var size = 1_000_000;
var executor = new StackallocExecutor(size);
executor.Stackalloc();
Have a nice day, bye!
Be First to Comment