gpt4 book ai didi

c# - Stackalloc 与 C# 中固定大小的缓冲区。有什么区别

转载 作者:行者123 更新时间:2023-12-05 02:37:32 30 4
gpt4 key购买 nike

就我而言,以下代码将在堆栈上创建一个数组:

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

stackalloc 语句会做同样的事情:

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

所以我想知道这些方法之间有什么区别。还有固定大小缓冲区的目的是什么?每个人都在谈论性能提升,但我不明白为什么我需要它们,而我已经可以使用 stackalloc 在堆栈上创建一个数组。 MSDN 说固定大小的缓冲区用于与其他平台“互操作”。那么这种“互操作”是什么样的呢?

最佳答案

fixed 语句仅表示数组内联(fixed inside)结构。这意味着存储在数组中的数据直接存储在您的结构中。在您的示例中,Foo 结构将具有存储 10 个整数值所需的大小。由于结构是值类型,因此它们分配在堆栈上。 但是当将它们存储在引用类型中时,它们也可以被复制到堆中。

class Test1
{
private Foo Foo = new();
}

unsafe struct Foo
{
public fixed int bar[10];
}

上面的代码将编译并且私有(private) Foo 实例将存在于托管堆上。

如果没有 fixed 语句(只是一个“普通”的 int[]),数组的数据将不会存储在结构本身中,而是存储在堆中。该结构将仅拥有对该数组的引用。

当使用 stackalloc 时,数据分配在堆栈上,不能由 CLR 自动移动到堆中。这意味着 stackalloc 的数据保留在堆栈中,编译器将通过不允许这样的代码来强制执行此操作:

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];
}
}

因此,当您绝对想确保分配的数据不会逃逸到堆中,从而导致抓取收集器的压力增加(这是性能问题)时,您可以使用 stackalloc。另一方面,fixed 主要用于与原生 C/C++ 库的互操作场景,这些库可能出于某种原因使用内联缓冲区。因此,当从 native 世界调用将带有内联缓冲区的结构作为参数的方法时,您必须能够在 .NET 中重新创建它,否则您将无法轻松地使用 native 代码(因此 fixed语句存在)。使用 fixed 的另一个原因是为了在结构中内联数据,这可以在 CPU 访问它时允许更好的缓存,因为它可以读取 Foo 中的所有数据无需取消引用引用并在内存中跳转即可访问存储在其他地方的某些数组。

关于c# - Stackalloc 与 C# 中固定大小的缓冲区。有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69943019/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com