Skip to content

Stackalloc – buffer on the stack

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!

Published in.NET

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *