我遇到了以下内容,摘自本书
约瑟夫·阿尔巴哈里和本·阿尔巴哈里(奥莱利)在果壳中的C#6.0。版权所有2016 Joseph Albahari和Ben Albahari,978-1-491-92706-9。
我没有看到它在那里提到,但是不遵循,那么,作为一个经验法则 - 你应该总是按照大小的降序声明你的类型中的变量,按顺序以避免记忆浪费被指出?
我的意思是,如果我做对了,我们通常应该在设计我们的类型时考虑到这一点。
更新:
我想出了下面的代码片段,以证明上述内容是对还是错。然而,我期待S2的大小不同(为了支持这本书的内容)。
public struct S1
{
public byte b;
public long l;
}
public struct S2
{
public long l;
public byte b;
}
[StructLayout(LayoutKind.Explicit, Size = 9)]
public struct S3
{
[FieldOffset(0)]
public byte b;
[FieldOffset(1)]
public long l;
}
S1 s1 = new S1();
S2 s2 = new S2();
S3 s3 = new S3();
Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(s1)); //prints 16
Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(s2)); //prints 16
Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(s3)); //prints 9
答案 0 :(得分:4)
这本书的摘录很容易让人误解。这意味着7个字节被“浪费”,但这与字段的顺序没有任何关系。您可以考虑交换订单,将long
成员放在第一位。但这并没有完成任何事情,那7个字节仍然未使用。
计算结构的布局和大小,以便长仍然与数组中的8对齐。换句话说,A []的元素也需要对齐。这只能在结构长度为16个字节时才能工作。换句话说,交换字段只是将未使用的7个字节移动到结构的末尾。
C#中的任何结构都有一个隐含的[StructLayout(LayoutKind.Sequential)]属性。您必须使用LayoutKind.Explicit强制有意错误对齐字段。请注意成本,未对齐的字段可能非常昂贵,读取和写入速度会降低x3。当字段跨越L1缓存行边界时发生。而且,如果处理器不支持未对齐的访问,那么就更多了,而今天的Itanium并没有出现太多问题。而且你失去了从CLR规范中获得的任何原子性保证。您不能故意错位引用垃圾收集器的引用类型(如字符串)的字段。
如果struct有3个或更多成员,它会变得更有趣。现在你可以通过订购它们来取得成功。就像一个long,int这样的字节,按顺序需要20个字节。如果重新排列为byte,int,而不是需要16个字节,则int适合填充。如果您使用LayoutKind.Auto覆盖,则CLR将为您执行此操作。