The sole reason to use stackalloc
is performance (either for computations or interop). By using stackalloc
instead of a heap allocated array, you create less GC pressure (the GC needs to run less), you don't need to pin the arrays down, it's faster to allocate than a heap array, an it is automatically freed on method exit (heap allocated arrays are only deallocated when GC runs). Also by using stackalloc
instead of a native allocator (like malloc or the .Net equivalent) you also gain speed and automatic deallocation on scope exit.
Performance wise, if you use stackalloc
you greatly increase the chance of cache hits on the CPU due to the locality of data.
I have used stackalloc to allocate buffers for [near] realtime DSP work. It was a very specific case where performance needed to be as consistent as possible. Note there is a difference between consistency and overall throughput - in this case I wasn't concerned with heap allocations being too slow, just with the non determinism of garbage collection at that point in the program. I wouldn't use it in 99% of cases.
stackalloc
is only relevant for unsafe code. For managed code you can't decide where to allocate data. Value types are allocated on the stack per default (unless they are part of a reference type, in which case they are allocated on the heap). Reference types are allocated on the heap.
The default stack size for a plain vanilla .NET application is 1 MB, but you can change this in the PE header. If you're starting threads explicitly, you may also set a different size via the constructor overload. For ASP.NET applications the default stack size is only 256K, which is something to keep in mind if you're switching between the two environments.
Stackalloc initialization of spans. In previous versions of C#, the result of stackalloc could only be stored into a pointer local variable. As of C# 7.2, stackalloc can now be used as part of an expression and can target a span, and that can be done without using the unsafe keyword. Thus, instead of writing
Span<byte> bytes;
unsafe
{
byte* tmp = stackalloc byte[length];
bytes = new Span<byte>(tmp, length);
}
You can write simply:
Span<byte> bytes = stackalloc byte[length];
This is also extremely useful in situations where you need some scratch space to perform an operation, but want to avoid allocating heap memory for relatively small sizes
Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>
Source: C# - All About Span: Exploring a New .NET Mainstay
There are some great answers in this question but I just want to point out that
Stackalloc can also be used to call native APIs
Many native functions requires the caller to allocate a buffer to get the return result. For example, the CfGetPlaceholderInfo function in cfapi.h
has the following signature.
HRESULT CfGetPlaceholderInfo(
HANDLE FileHandle,
CF_PLACEHOLDER_INFO_CLASS InfoClass,
PVOID InfoBuffer,
DWORD InfoBufferLength,
PDWORD ReturnedLength);
In order to call it in C# through interop,
[DllImport("Cfapi.dll")]
public static unsafe extern HResult CfGetPlaceholderInfo(IntPtr fileHandle, uint infoClass, void* infoBuffer, uint infoBufferLength, out uint returnedLength);
You can make use of stackalloc.
byte* buffer = stackalloc byte[1024];
CfGetPlaceholderInfo(fileHandle, 0, buffer, 1024, out var returnedLength);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With