简体   繁体   English

Stackalloc 与 C# 中固定大小的缓冲区。 有什么不同

[英]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: stackalloc 语句会做同样的事情:

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.每个人都在谈论性能提升,但我不明白为什么我需要它们,因为我已经可以使用 stackalloc 在堆栈上创建一个数组。 MSDN says that fixed sized buffers are used to "interoperate" with other platforms. MSDN 说固定大小的缓冲区用于与其他平台“互操作”。 So what is this "interoperation" looks like?那么这个“互操作”是什么样子的呢?

The fixed statement only says that an array is inlined ( fixed inside) the struct. fixed语句仅说明数组已内联(固定在结构体内部)。 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.在您的示例中, Foo结构将具有存储 10 个整数值所需的大小。 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.上面的代码将被编译并且私有Foo实例将存在于托管堆中。

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.如果没有固定语句(只是一个“正常”的 int[]),数组的数据将不会存储在结构本身中,而是存储在堆中。 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.使用stackalloc ,数据在堆栈上分配,不能由 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).因此,当您绝对想确保分配的数据不能逃逸到堆中时,您可以使用stackalloc ,从而导致抓取收集器的压力增加(这是一个性能问题)。 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.另一方面, fixed主要用于与本机C/C++库的互操作场景,这些库可能出于某种原因使用内联缓冲区。 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).因此,当从本机世界调用将带有内联缓冲区的结构作为参数的方法时,您必须能够在 .NET 中重新创建它,否则您将无法轻松使用本机代码(因此存在fixed语句)。 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.使用fixed另一个原因是内联结构中的数据,这可以在 CPU 访问它时进行更好的缓存,因为它可以一次性读取Foo中的所有数据,而无需取消引用引用并在内存中跳转访问存储在别处的一些数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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