16

当您需要非常小的对象时,比如说包含 2 个 float 属性,并且您将拥有数百万不会立即“销毁”的对象,是结构体还是类更好的选择?

就像在 xna 作为一个库一样,有 point3s 等作为结构,但是如果你需要长时间保持这些值,它会不会对性能造成威胁?

4

6 回答 6

34

与大多数关于结构的问题相反,这实际上似乎是结构的一个很好的用途。如果它包含的数据是值类型,并且您将使用其中的很多,那么结构会很好地工作。

一些技巧:

:: struct 不应大于 16 字节,否则您将失去性能优势。

:: 使结构不可变。这使得使用更加清晰。

例子:

public struct Point3D {

   public float X { get; private set; }
   public float Y { get; private set; }
   public float Z { get; private set; }

   public Point3D(float x, float y, float z) {
      X = x;
      Y = y;
      Z = z;
   }

   public Point3D Invert() {
      return new Point3D(-X, -Y, -Z);
   }

}
于 2009-03-03T22:14:24.657 回答
5

答案取决于最终将存储对象/值的位置。如果要将它们存储在像 ArrayList 这样的无类型集合中,那么您最终将它们装箱。装箱为结构创建对象包装器,占用空间与类对象相同。另一方面,如果您使用 T[] 或 List 之类的类型化数组,那么使用结构将仅存储每个元素的实际数据,并且仅存储整个集合而不是其元素的足迹。

因此,在 T[] 数组中使用结构更有效。

于 2009-03-03T22:14:26.793 回答
2

最大的问题是内存是分配在堆栈还是堆上。默认情况下,结构体进入堆栈,并且堆栈通常在空间方面受到更多限制。所以像这样创建一大堆结构可能是个问题。

不过,在实践中,我真的不认为这有什么大不了的。如果你有那么多它们,它们很可能是某个类实例(在堆上)的一部分。

于 2009-03-03T22:08:38.163 回答
2

Struct 似乎适合这个应用程序。

请记住,“需要保留这些值”意味着它们存储在堆上的某个地方,可能是类实例的数组字段。

需要注意的一件事是,这会导致在大对象堆上进行分配。目前尚不清楚该堆如何进行碎片整理(如果有的话),但是对于寿命很长的对象来说,这可能不是问题。

对数以百万计的这些数据类型使用类可能会因为取消引用的剪切量而代价高昂,这可能会发生在这种类型的操作上。

于 2009-03-03T22:10:16.647 回答
2

通常,相同类型的大型非别名(即非共享)数据数组最好存储在结构中以提高性能,因为您减少了间接次数。(另请参见when-are-structs-the-answer)。class 和 struct 之间的确切性能差异取决于您的使用情况。(例如,在操作中,您是否只访问结构的一部分?您是否进行了大量临时复制?如果结构很小,使用它可能总是更好,但如果它很大,创建临时副本可能会减慢您的速度。如果您使其不可变,您将必须始终复制整个内容以更改值。)

如有疑问,请测量。

由于您对此类测量可能不明显的可能的长期影响感兴趣,因此请注意此类数组可能存储在大对象堆上,应该重复使用而不是销毁和重新分配。(请参阅CRL 由内而外:发现大型对象堆。)

在调用中传递较大尺寸的结构时,您可能希望使用 ref 参数传递它们以避免复制。

于 2009-03-04T03:06:22.363 回答
1

值类型(结构)适用于不经常在堆上分配的类型,也就是说,它们大多包含在另一个引用或值类型中。

您提供的 Vector3 示例是一个完美的示例。您很少会在堆中悬挂 Vector3,它们大多数时候将包含在本身在堆中的类型中,或者用作局部变量,在这种情况下,它将被分配在堆栈上。

于 2009-03-03T22:09:15.963 回答