5

我不希望提高性能或内存使用率,这个问题纯粹是出于好奇。

主要问题 给定以下类,C# 编译器(Mono + .NET)会将这两个short变量打包成 4 个字节,还是它们会消耗 8 个字节(对齐)?

public class SomeClass {
    short a;
    short b;
}

次要问题 如果上述问题的答案不是 4 个字节,那么以下替代方案是否会提供任何优势(其中SomeClass大量使用):

// Warning, my bit math might not be entirely accurate!
public class SomeClass {
    private int _ab;

    public short a {
        get { return _ab & 0x00ff; }
        set { _ab |= value & 0x00ff;
    }
    public short b {
        get { return _ab >> 8; }
        set { _ab |= value << 8; }
    }
}
4

3 回答 3

6

正如@David_M 所说,它取决于运行时,但您可以通过使用具有可用于控制打包[StructLayout]的成员的属性来强制它。Pack或者,您可以使用[FieldOffset]手动布局结构的成员(甚至重叠,这是您在 .NET 中实现联合的方式)。

于 2012-06-21T15:01:00.463 回答
5

这取决于运行时,而不是编译器。您可以使用 覆盖默认行为[StructLayout],这会有所帮助 - 尽管默认行为应该没问题。

话虽如此,如果最小化总大小是绝对要求,您可能需要考虑 astruct而不是 a class。使用类时,类的每个实例都会增加大量开销。在 syncblk、TypeHandle 等以及引用(在 64 位系统上是另外 8 个字节)对象实例之间使用了相当数量的“额外”内存,超出了您的两条短裤。有关详细信息,请参阅“CLR 如何创建运行时对象”

将打包的数据存储到值类型的集合中可以完全避免这种情况,并使每个实例总共减少到 8 个字节(加上集合开销)。当然,这会在使用方面改变语义,但如果您只使用两个短裤,这将减少您的类型所涉及的开销,尤其是在 64 位系统上。

于 2012-06-21T15:03:25.190 回答
2

正如其他人所评论的那样,实际布局取决于运行时,主要是因为您可以跨多个平台运行相同的代码。

是的,如果有许多可以节省空间的对象。您正在寻找的是 LayoutKind (StructLayout 属性)。它可以让您随心所欲地打包成员。例如,使用 Sequential 时,它会确保它被打包得很紧。

[StructLayout(LayoutKind.Sequential)]
public class SomeClass {
    short a;
    short b;
}

有关更多信息,请查看MSDN-Structlayout

于 2012-06-21T15:01:10.190 回答