结构是否比类"更快" - 一般情况下还是在.NET框架中?

Tim*_*uri 17 .net memory-management data-structures

由于结构是值类型,因此在将数据作为参数传递给方法时会复制它们的数据.例:

int someInt = 7;

DoSomeMethod(someInt); // <-- This is passing the "value" 7.
Run Code Online (Sandbox Code Playgroud)

到目前为止,很容易理解,你可能想知道我的问题是如何有效的......所以请考虑以下几点:

public struct TimmysStructOfGoodness
{
    public int SomeInt1;
    public int SomeInt2;
    public int SomeInt3;
    // ... later that day ...
    public int SomeInt999;
}
Run Code Online (Sandbox Code Playgroud)

然后,参考以下代码:

TimmysStructOfGoodness someStructOfGoodness = new blah blah blah...

DoSomeMethod(someStructOfGoodness); // <-- **HERE IS WHERE THE QUESTION APPLIES!**
Run Code Online (Sandbox Code Playgroud)

上面的语句是否试图分配几个内存来"复制"我的值类型(struct)?

如果答案是肯定的 - 那么何时/哪里是"更快"和"更慢"之间的界线?

如果不是 - 那为什么不呢?因为我所知道的价值类型,这应该是一个问题.

主要免责声明:我知道这与你为什么要使用一个类的结构无关,而且我知道我永远不会用999个字段创建一个结构 - 这只是一个基本的内部和内部等问题: )

yu_*_*sha 14

(更新,感谢其他用户的贡献)

与类不同,struct是在堆栈上创建的.因此,实例化(和销毁)结构比使用类更快.

除非(正如Adam Robinson指出的那样)struct是一个类成员,在这种情况下,它与堆中的所有其他内容一起分配.

另一方面,每次分配结构或将其传递给函数时,都会复制它.

我不认为结构大小有一个硬性限制.成千上万的字节肯定太多了.MSDN :

除非您需要引用类型语义,否则系统可以更有效地将小于16字节的类作为结构进行处理.

这是 - 如果你需要通过引用传递它,使它成为一个类,无论大小.

在第二个想法中,您仍然可以通过在函数参数列表中指定ref来通过引用传递struct.

因此,如果通过引用传递它并将其用作类成员,那么大型结构实际上可以正常.

  • 这不完全准确......在堆栈上声明了本地结构; 任何实例变量(或静态变量)仍将在堆上声明,就像任何其他实例或静态成员一样. (7认同)
  • 由于问题是关于性能,我们必须研究实现细节.除非实际实施,否则没有语言表现这样的东西. (3认同)
  • 此外,根据Eric Lippert的说法,"堆栈是一个实现细节." http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx不是语言功能. (2认同)

Mar*_*ers 8

结构和类不仅具有不同的性能,它们的行为也不同.您应该使用最适合您正在实现的类型的那个.在MSDN清楚地描述了何时使用其中一个或一个的指南.仅当以下所有条件适用时才使用结构:

  • 它逻辑上表示单个值,类似于基本类型(整数,双精度等).
  • 它的实例大小小于16个字节.
  • 这是不可改变的.
  • 它不必经常装箱.

如果要将结构传递给函数,您将获得它的副本.如果你的结构很大,那么它将导致复制大量数据.引用通常实现为4个字节(在x86上),因此传递对象只需要复制这4个字节.

另请注意,上述指南要求结构很小.

  • -1.虽然信息是正确的,但他明确表示他不会*讨论(也不感兴趣)结构与类的不同用例. (4认同)
  • @Adam Robinson:当然,问题就像问"哪个更快,在公园里悠闲地散步,还是开车到电影院观看你最喜欢的电影?" 你可以花时间去看哪个更快,但由于两者不是完全可互换的,因此比较并不一定有意义.我认为值得指出的是,如果不是海报,还有其他读者. (2认同)

LBu*_*kin 6

结构的性能影响取决于您如何使用这些结构.

关于结构是否比参考类型更快或更慢,不可能做出明确的陈述.这一切都取决于你如何使用它们,以及在什么情况下.

结构(一般的值类型)最终可以在堆栈或堆上分配 - 具体取决于它们的声明上下文.如果在方法的主体中声明它(并且没有明确地将其封装),结构将最终在堆栈上.如果然后将该结构传递给按值接受它的方法(如在您的示例中),它确实将被复制 - 但在堆栈上.堆栈上的分配是一个非常有效的过程(BTW,.NET堆也非常有效) - 但它是一个复制过程.

当然,您可以使用ref/out传递结构 - 在这种情况下不会发生复制 - 对结构的引用将传递给方法.这可能是,也可能不是,因为它将允许被调用的方法改变结构的内容.

声明为类成员的结构实际上将在堆上分配(作为类的内存布局的一部分).如果您传递该类,则不会复制该结构,但仍可通过类引用访问该结构.

您还可以通过显式装箱来获取堆上的结构:

object x = new MyStruct( ... );  // boxed on the heap
Run Code Online (Sandbox Code Playgroud)

Jon Skeet有一篇很好的文章,关于你应该阅读的内存最终的内容.