[英]Drawing a Path in XAML (with binding) vs. C#. One works, one doesn't
[英]Stackalloc vs. Fixed sized buffer in C#. What is the difference
就我而言,以下代码将在堆栈上创建一个数组:
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
语句仅说明数组已内联(固定在结构体内部)。 这意味着存储在数组中的数据直接存储在您的结构中。 在您的示例中, Foo
结构将具有存储 10 个整数值所需的大小。 由于结构是值类型,因此它们被分配在堆栈上。 然而,它们也可以被复制到堆中,例如将它们存储在引用类型中。
class Test1
{
private Foo Foo = new();
}
unsafe struct Foo
{
public fixed int bar[10];
}
上面的代码将被编译并且私有Foo
实例将存在于托管堆中。
如果没有固定语句(只是一个“正常”的 int[]),数组的数据将不会存储在结构本身中,而是存储在堆中。 该结构将只拥有对该数组的引用。
使用stackalloc
,数据在堆栈上分配,不能由 CLR 自动移动到堆中。 这意味着堆栈分配的数据保留在堆栈上,编译器将通过不允许这样的代码来强制执行此操作:
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++
库的互操作场景,这些库可能出于某种原因使用内联缓冲区。 因此,当从本机世界调用将带有内联缓冲区的结构作为参数的方法时,您必须能够在 .NET 中重新创建它,否则您将无法轻松使用本机代码(因此存在fixed
语句)。 使用fixed
另一个原因是内联结构中的数据,这可以在 CPU 访问它时进行更好的缓存,因为它可以一次性读取Foo
中的所有数据,而无需取消引用引用并在内存中跳转访问存储在别处的一些数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.