首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#中的Stackalloc与固定大小的缓冲区。有什么区别

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

Stack Overflow用户
提问于 2021-11-12 12:32:34
回答 1查看 749关注 0票数 3

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

代码语言:javascript
复制
unsafe struct Foo 
{ 
   public fixed int bar[10]; 
}
var foo = new Foo();

stackalloc语句也会做同样的事情:

代码语言:javascript
复制
public void unsafe foo(int length)
{
    Span<int> bar = stackalloc int[length];
}

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-12 13:40:40

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

代码语言:javascript
复制
class Test1
{
    private Foo Foo = new();
}

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

上面的代码将编译,私有Foo实例将在托管堆上运行。

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

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

代码语言:javascript
复制
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中的所有数据,而不必取消引用并跳过内存来访问存储在其他地方的数组。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69943019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档