您声明类变量的顺序是否会影响内存的分配方式?

时间:2016-07-17 15:37:05

标签: c# clr

我遇到了以下内容,摘自本书

  约瑟夫·阿尔巴哈里和本·阿尔巴哈里(奥莱利)在果壳中的C#6.0。

     

版权所有2016 Joseph Albahari和Ben Albahari,978-1-491-92706-9。

enter image description here

我没有看到它在那里提到,但是不遵循,那么,作为一个经验法则 - 你应该总是按照大小的降序声明你的类型中的变量,按顺序以避免记忆浪费被指出?

我的意思是,如果我做对了,我们通常应该在设计我们的类型时考虑到这一点。

更新:

我想出了下面的代码片段,以证明上述内容是对还是错。然而,我期待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

1 个答案:

答案 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将为您执行此操作。