简体   繁体   中英

Stackalloc vs. Fixed sized buffer in C#. What is the difference

As far as I'm concerned the following code will create an array on the stack:

unsafe struct Foo 
{ 
   public fixed int bar[10]; 
}
var foo = new Foo();

And stackalloc statement will do the same thing:

public void unsafe foo(int length)
{
    Span<int> bar = stackalloc int[length];
}

So I'm wondering what is the difference between those approaches. And also what is the purpose of fixed size buffers at all? Everyone talks about performance boost, but I can not understand why do I need them, when I already can create an array on the stack with stackalloc. MSDN says that fixed sized buffers are used to "interoperate" with other platforms. So what is this "interoperation" looks like?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM