【问题标题】:Why does an array of classes consume ~20% more memory than array of structs?为什么类数组比结构数组消耗约 20% 的内存?
【发布时间】:2012-08-12 03:00:12
【问题描述】:

我正在制作一个 2D 平台游戏,为了表示一个级别,我使用了 2D 瓦片数组,这些瓦片是具有位置、类型和各种标志字段的类。当我将 tile 类中的 class 关键字更改为 struct 时,加载的地图消耗的内存减少了大约 20%。

我不知道这个动作的对错,我只想知道为什么内存消耗的差异。

编辑:数字为 1038 MB,其中 tile 作为类,845 MB 作为结构(没有大部分游戏数据)。​​

【问题讨论】:

  • 因为 .Net 结构比 .Net 类“更轻”。 20%似乎有点过分了。但是创建(例如)“类”对象的 1,000K 实例比创建等效“结构”对象的 1,000K 实例使用更多的内存......
  • 看起来您可能正在考虑使用可变结构(如果我理解“标志”变量)。为了你自己的理智,不要。 stackoverflow.com/questions/441309/why-are-mutable-structs-evil
  • 这里有大量关于类与结构的信息:stackoverflow.com/questions/521298/when-to-use-struct-in-c
  • 您的 20% 数字很难解释,因为您没有告诉我们每个结构中有多少字节的有效负载。
  • 1GB 用于游戏中的瓦片基础地图无论如何都有些愚蠢。

标签: c# arrays class struct


【解决方案1】:

结构类型的存储位置(变量、参数、数组元素或字段)保存其所有公共和私有字段的值,通常连接在一起,但可能带有一些填充。类类型的存储位置包含对堆对象(4-8 字节)的(可能为空)引用。一个堆对象拥有 8-16 字节的开销,以及该对象及其祖先拥有的所有公共、受保护和私有字段的内容。

如果你存储的东西是固定大小的值包,你应该最有可能使用带有暴露字段的结构。结构应该是不可变的概念可以追溯到 C# 编译器采用如下代码的时代:

只读点 Pt = new Point(3,4); 无效 Yippie() { Pt.X += 5; }

并让Yippie 构造一个新的临时Point,将Pt 复制到它,在该临时实例上调用X 属性设置器,然后丢弃它。有人认为防止这种废话的正确方法不是让编译器说“对不起——你不能在只读结构变量上调用属性设置器”,而是定义结构以便具有只读属性没有二传手。正确的做法是要求任何将要改变this 的结构方法或属性在其声明中表明这一点,并禁止在只读结构上使用此类方法或属性。

在属性中包装结构字段会损害性能,我建议不要这样做,除非需要强制执行结构不变量。我还建议避免声明结构readonly,因为如此声明的任何结构都将在任何时候访问任何字段时被完整复制。

顺便提一下,对于可变类类型需要注意的重要一点:可变类对象的状态不仅包括其字段的内容,还包括对其存在的所有引用的集合 .在某些情况下,这可能很有用。通常,避免重大问题的唯一方法是让持有对可变对象的引用的实体避免共享此类引用。如果将某个东西设为类类型需要额外的工作来防止引用被乱七八糟地传递,那么这是一个好兆头,表明所讨论的类型应该是一个结构。

【讨论】:

    【解决方案2】:

    对象数组其实就是引用数组,对象存放在堆上。

    这意味着引用有 4 或 8 个字节(取决于 x86 或 x64)的开销,然后堆上的每个对象有 8 或 16 个字节的开销。

    在结构体数组中,结构体值直接存储在数组中,因此没有额外的开销。

    因此,例如,如果您的数据是 48 字节,那么额外的 12 字节(在 x86 模式下)将是所用总内存的 20% 的开销。

    请注意,它们的使用方式也有所不同。如果您移动磁贴或将磁贴作为参数发送给方法,则如果使用结构,则将复制所有数据,但如果使用类,则仅复制引用。如果可以将结构保持在 16 字节以下,则性能差异很小,但如果更大,则可以通过使用类获得更快的代码。

    【讨论】:

      【解决方案3】:

      每个对象都有一个 8 字节的标头,其中包含指向类型句柄和同步块索引的指针,而结构是内联分配的。此外,您需要为您使用的每个引用类型变量分配一个指针大小的引用。

      This article 详细介绍了如何在运行时创建对象和布局。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-09
        • 2016-01-05
        • 1970-01-01
        • 1970-01-01
        • 2011-04-12
        相关资源
        最近更新 更多