结构是否比类“更快” - 通常还是在.NET框架中?

时间:2009-12-28 16:38:34

标签: .net data-structures memory-management

由于结构是值类型,因此当作为参数传递给方法时,它们的数据被复制。例如:

int someInt = 7;

DoSomeMethod(someInt); // <-- This is passing the "value" 7.

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

public struct TimmysStructOfGoodness
{
    public int SomeInt1;
    public int SomeInt2;
    public int SomeInt3;
    // ... later that day ...
    public int SomeInt999;
}

然后,参考以下代码:

TimmysStructOfGoodness someStructOfGoodness = new blah blah blah...

DoSomeMethod(someStructOfGoodness); // <-- **HERE IS WHERE THE QUESTION APPLIES!**

上述语句是否尝试分配几个ram来“复制”我的值类型(struct)?

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

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

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

5 个答案:

答案 0 :(得分:12)

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

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

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

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

我认为结构大小没有硬性限制。成千上万的字节肯定太多了。 MSDN says

  

除非您需要参考类型   语义,一个较小的类   超过16个字节可能更有效   由系统处理为结构。

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

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

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

答案 1 :(得分:9)

结构和类不仅具有不同的性能,它们的行为也不同。您应该使用最适合您正在实现的类型的那个。何时使用其中一个的准则是clearly described on MSDN。仅在满足以下所有条件时才使用结构:

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

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

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

答案 2 :(得分:6)

结构的性能影响取决于您如何使用此类结构。

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

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

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

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

您还可以通过显式装箱将结构体添加到堆中:

object x = new MyStruct( ... );  // boxed on the heap

Jon Skeet有一个很好的article about where things end up in memory你应该阅读。

答案 3 :(得分:3)

为了增加混乱,请记住,如果您不需要将副本传递给另一个方法,您始终可以通过引用传递结构以避免复制...

答案 4 :(得分:2)

你的问题的答案是:是的。定义结构时,每个赋值都会产生一个复制操作。

没有确切的行将“快”和“慢”分开,因为有很多因素影响速度WRT到结构,例如:

&LT;校正&GT; 结构按值存储在堆栈上或包含对象内。因此,它们会提升缓存局部性,因为相关页面已经加载到CPU的缓存中,而任意堆页面很可能都没有。 &LT; /校正&GT;此外,结构不允许方法覆盖,因此方法调度也(稍微)更快。

另一方面,每个作业都会产生一份副本。因此,如果您的代码有很多分配,那么上述优势将被复制操作的成本所抵消。从一个程序到另一个程序的收支平衡点不同(由于缓存局部性,方法调度和分配的不同特征)

相关问题