为什么.NET结构应该少于16个字节?

时间:2009-07-04 14:36:47

标签: c# .net

我现在已经在几个地方读过结构的最大实例大小应该是16个字节。

但我看不出这个数字(16)的来源。

浏览网络,我发现一些人认为这是一个近似的数字表现良好,但微软说这是一个很难的上限。 (例如MSDN

有没有人对16字节的原因有明确的答案?

6 个答案:

答案 0 :(得分:60)

这只是一个表现法则。

关键是因为值类型是按值传递的,所以如果将结构传递给函数,则必须复制结构的整个大小,而对于引用类型,只需要复制引用(4个字节) 。结构可能会节省一些时间,因为你删除了一个间接层,所以即使它大于这4个字节,它仍然比传递引用更有效。但在某些时候,它变得如此之大,以至于复制的成本变得明显。一个常见的经验法则是,这通常发生在大约16个字节。之所以选择16是因为它是一个很好的整数,2的幂,并且替代是8(这太小了,会使结构几乎无用),或32(此时复制结构的成本已经成问题)如果出于性能原因使用结构体

但最终,这是性能建议。它回答了“哪个使用效率最高?结构或类?”的问题。但它没有回答“哪个最佳映射到我的问题域”的问题。

结构和类的行为不同。如果你需要一个struct的行为,那么我会说它是一个结构,无论大小。至少在遇到性能问题之前,请对代码进行概要分析,并发现结构存在问题。

您的链接甚至表示这仅仅是性能问题:

  

如果这些条件中的一个或多个是   没有遇到,创建一个引用类型   而不是一个结构。没有   坚持这个准则可以   对绩效产生负面影响。

答案 1 :(得分:26)

如果结构不大于16个字节,可以使用一些简单的处理器指令进行复制。如果它更大,则使用循环来复制结构。

只要结构不超过16个字节,处理器在复制结构时就像复制引用时一样。如果结构较大,则会失去具有s结构的性能优势,而且通常应该将其改为类。

答案 2 :(得分:23)

大小数字主要来自在堆栈上复制结构所花费的时间,例如传递给方法。任何比这更大的东西,你只是在消耗大量的堆栈空间和CPU周期而只是复制数据 - 当一个对不可变类的引用(甚至使用解除引用)可能会更高效。

答案 3 :(得分:8)

正如其他答案所指出的那样,复制结构的每字节成本大于某个阈值(在早期版本的.NET中为16字节,但后来增长到20-24)远远大于较小结构的每字节成本。然而,重要的是要注意,复制任何特定大小一次的结构将是创建相同大小的新类对象实例的成本的一小部分。如果在其生命周期中多次复制结构,并且不特别需要值类型语义,则类对象可能是优选的。但是,如果结构最终只被复制一次或两次,那么这种复制可能比创建新的类对象便宜。类对象变得更便宜的收支平衡数量随着所讨论的结构/对象的大小而变化,但是对于低于“廉价复制”阈值的事物而言比上面的事情要高得多。

BTW,值得一提的另一点是,将结构作为ref参数传递的成本与结构的大小无关。在许多情况下,可以通过使用值类型并通过ref传递它们来实现最佳性能。但是,必须小心避免使用属性或结构类型的readonly字段,因为访问其中任何一个都将创建相关结构的隐式临时副本。

答案 4 :(得分:1)

这是一种结构可以表现出卓越性能的场景:

当您需要创建1000个实例时。在这种情况下,如果您要使用类,则首先需要分配数组以容纳1000个实例,然后在循环中分配每个实例。但是,如果你要使用结构,那么在分配将要保存它们的数组后,1000个实例立即可用。

此外,当您出于性能原因需要进行互操作或想要使用不安全的代码时,结构非常有用。

一如既往需要权衡,需要分析他们正在做的事情,以确定实施某些事情的最佳方式。

ps:当我使用LIDAR数据时,这个场景开始发挥作用,其中可能有数百万个点代表地面数据的x,y,z和其他属性。需要将这些数据加载到内存中进行一些密集计算,以输出各种内容。

答案 5 :(得分:0)

从性能的角度来看,我认为16字节只是一个经验法则。 .NET中的一个对象使用至少24个字节的内存(IIRC),因此如果你的结构比那个大得多,那么引用类型会更好。

我想不出他们为什么特意选择了16个字节的原因。