【发布时间】:2010-11-08 02:43:14
【问题描述】:
我已经在几个地方读到,结构的最大实例大小应该是 16 字节。
但我看不出那个数字 (16) 是从哪里来的。
在网上浏览时,我发现一些人认为这是表示良好性能的近似数字,但微软认为这是一个硬性上限。 (例如MSDN)
有人对为什么它是 16 字节有明确的答案吗?
【问题讨论】:
我已经在几个地方读到,结构的最大实例大小应该是 16 字节。
但我看不出那个数字 (16) 是从哪里来的。
在网上浏览时,我发现一些人认为这是表示良好性能的近似数字,但微软认为这是一个硬性上限。 (例如MSDN)
有人对为什么它是 16 字节有明确的答案吗?
【问题讨论】:
如果一个结构不大于 16 字节,则可以使用一些简单的处理器指令来复制它。如果较大,则使用循环来复制结构。
只要结构不大于 16 字节,处理器在复制结构时必须执行与复制引用时相同的工作。如果结构较大,您将失去拥有结构的性能优势,通常应该将其改为类。
【讨论】:
正如其他答案所指出的,复制大于某个阈值(在早期版本的 .NET 中为 16 个字节,但后来增长到 20-24 个字节)的结构的每字节成本明显高于较小结构的每字节成本。然而,重要的是要注意,复制 any 特定大小的结构 once 将只是创建相同大小的新类对象实例成本的一小部分。如果一个结构在其生命周期中会被复制很多次,并且值类型语义不是特别需要,那么类对象可能更可取。然而,如果一个结构最终只被复制一次或两次,那么这种复制可能比创建一个新的类对象更便宜。类对象变得更便宜的盈亏平衡数量随所讨论的结构/对象的大小而变化,但对于低于“廉价复制”阈值的东西,比上面的东西要高得多。
顺便说一句,另一点值得一提的是,将结构作为ref 参数传递的成本与结构的大小无关。在许多情况下,可以通过使用值类型并通过ref 传递它们来实现最佳性能。但是,必须小心避免使用结构类型的属性或 readonly 字段,因为访问其中任何一个都会创建相关结构的隐式临时副本。
【讨论】:
readonly 字段。你能给我指向一个链接以供进一步阅读吗?
这是结构可以表现出卓越性能的场景:
当您需要创建 1000 个实例时。在这种情况下,如果您要使用一个类,您首先需要分配数组来保存 1000 个实例,然后在循环中分配每个实例。但是,如果您要使用结构,那么在您分配要保存它们的数组后,这 1000 个实例将立即可用。
此外,当您需要进行互操作或出于性能原因想要深入了解不安全的代码时,结构非常有用。
与往常一样,需要权衡取舍,需要分析他们正在做的事情,以确定实施某事的最佳方式。
ps:当我使用 LIDAR 数据时,这种情况开始发挥作用,其中可能有数百万个点表示 x、y、z 和地面数据的其他属性。需要将这些数据加载到内存中进行一些密集计算以输出各种内容。
【讨论】:
这只是一个经验法则。
关键是因为值类型是按值传递的,如果将结构体传递给函数,则必须复制整个结构的大小,而对于引用类型,只需复制引用(4字节) .虽然结构可能会节省一些时间,因为您删除了一层间接,因此即使它大于这 4 个字节,它仍然可能比传递引用更有效。但在某些时候,它变得如此之大,以至于复制成本变得显而易见。一个常见的经验法则是,这通常发生在 16 个字节左右。选择 16 是因为它是一个很好的整数,是 2 的幂,备选方案是 8(太小,会使结构几乎无用)或 32(此时复制结构的成本已经成问题如果您出于性能原因使用结构)
但归根结底,这是性能建议。它回答了“使用哪个最有效?结构还是类?”的问题。但它没有回答“哪个最好映射到我的问题域”的问题。
结构和类的行为不同。如果你需要一个结构的行为,那么我会说让它成为一个结构,不管大小。至少在您遇到性能问题之前,分析您的代码并发现您的结构存在问题。
您的链接甚至说这只是性能问题:
如果这些条件中的一个或多个 不满足,创建引用类型 而不是结构。未能 遵守本指南即可 对性能产生负面影响。
【讨论】:
大小数字主要来自复制堆栈上的结构所需的时间,例如传递给方法。任何比这大得多的东西,并且仅复制数据就会消耗大量堆栈空间和 CPU 周期 - 当对不可变类的引用(即使取消引用)可能会更有效。
【讨论】:
我认为从性能的角度来看,16 个字节只是一个经验法则。 .NET 中的对象至少使用 24 字节的内存 (IIRC),所以如果你的结构比这大得多,那么引用类型会更好。
我想不出他们为什么专门选择 16 字节。
【讨论】: