The fixed
statement only says that an array is inlined (fixed inside) the struct. Meaning the data stored in the array is directly stored in your struct. In your example the Foo
struct would have the size needed to store 10 integer values. As structs are value types they are allocated on the stack. However they can also be copied to the heap when for example storing them in a reference type.
class Test1
{
private Foo Foo = new();
}
unsafe struct Foo
{
public fixed int bar[10];
}
The code above will compile and the private Foo
instance will live on the managed heap.
Without the fixed statement (just a "normal" int[]) the data of the array would not be stored in the struct itself but on the heap. The struct would only own a reference to that array.
When using stackalloc
the data is allocated on the stack and cannot be automatically moved to the heap by the CLR. This means that stackalloc'ed data remains on the stack and the compiler will enforce this by not allowing code like this:
unsafe class Test1
{
// CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct.
private Span<int> mySpan;
public Test1()
{
// CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method
mySpan = stackalloc int[10];
}
}
Therefore you use stackalloc
when you absolutely want to make sure that your allocated data can not escape to the heap resulting in increased pressure on the grabage collector (it's a performance thing). fixed
on the other hand is mainly used for interop scenarios with native C/C++
libraries which may use inlined buffers for some reason or another. So when calling methods from the native world which take structs with inlined buffers as a parameter you must be able to recreate this in .NET or else you wouldn't be able to easily work with native code (thus the fixed
statement exists). Another reason to use fixed
is for inlining the data in your struct which can allow for better caching when the CPU is accessing it as it can just read all the data in Foo
in one go without having to dereference a reference and jump around the memory to access some array stored elsewhere.
stackalloc
lets the size of the allocated array be dynamic – Nosedive