C#学习教程:CLR顺序结构布局:对齐和大小分享


CLR顺序结构布局:对齐和大小

默认情况下,C#中的所有struct都被视为[StructLayout(LayoutKind.Sequential)]标记的值类型。 所以让我们采取一些struct并检查这个struct的大小:

 using System; using System.Reflection; using System.Linq; using System.Runtime.InteropServices; class Foo { struct E { } struct S0 { byte a; } struct S1 { byte a; byte b; } struct S2 { byte a; byte b; byte c; } struct S3 { byte a; int b; } struct S4 { int a; byte b; } struct S5 { byte a; byte b; int c; } struct S6 { byte a; int b; byte c; } struct S7 { int a; byte b; int c; } struct S8 { byte a; short b; int c; } struct S9 { short a; byte b; int c; } struct S10 { long a; byte b; } struct S11 { byte a; long b; } struct S12 { byte a; byte b; short c; short d; long e; } struct S13 { E a; E b; } struct S14 { E a; E b; int c; } struct S15 { byte a; byte b; byte c; byte d; byte e; } struct S16 { S15 b; byte c; } struct S17 { long a; S15 b; } struct S18 { long a; S15 b; S15 c; } struct S19 { long a; S15 b; S15 c; E d; short e; } struct S20 { long a; S15 b; S15 c; short d; E e; } static void Main() { Console.WriteLine("name: contents => sizen"); foreach (var type in typeof(Foo).GetNestedTypes(BindingFlags.NonPublic)) { var fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance); Console.WriteLine("{0}: {2} => {1}", type.Name, Marshal.SizeOf(type), string.Join("+", fields.Select(_ => Marshal.SizeOf(_.FieldType)))); } } } 

输出是(x86 / x64上相同):

 name: contents => size E: => 1 S0: 1 => 1 S1: 1+1 => 2 S2: 1+1+1 => 3 S3: 1+4 => 8 S4: 4+1 => 8 S5: 1+1+4 => 8 S6: 1+4+1 => 12 S7: 4+1+4 => 12 S8: 1+2+4 => 8 S9: 2+1+4 => 8 S10: 8+1 => 16 S11: 1+8 => 16 S12: 1+1+2+2+8 => 16 S13: 1+1 => 2 S14: 1+1+4 => 8 S15: 1+1+1+1+1 => 5 S16: 5+1 => 6 S17: 8+5 => 16 S18: 8+5+5 => 24 S19: 8+5+5+1+2 => 24 S20: 8+5+5+2+1 => 24 

看看这个结果我无法理解用于顺序结构的布局(字段对齐和总大小)规则集CLR。 有人能解释一下这种行为吗?

所有字段都根据其类型对齐。 本机类型( intbyte等)都按其大小对齐。 例如, int将始终为4个字节的倍数,而一个字节可以是任何位置。

如果较小的字段位于int之前,则必要时将添加填充以确保int正确对齐到4个字节。 这就是为什么S5 (1 + 1 + 4 = 8)和S8 (1 + 2 + 4 = 8)将具有填充并最终相同的大小:

 [1][1][ ][ ][4] // S5 [1][ ][ 2 ][4] // S8 

另外,struct本身inheritance了其最对齐字段的对齐(即,对于S5S8int是最对齐的字段,因此它们都具有4的对齐)。 对齐是这样inheritance的,这样当你有一个结构数组时,所有结构中的所有字段都将正确对齐。 所以,4 + 2 = 8。

 [4][2][ ][ ] // starts at 0 [4][2][ ][ ] // starts at 8 [4][2][ ][ ] // starts at 16 

请注意,4始终对齐4.如果不inheritance最对齐的字段,则数组中的每个其他元素的int对齐6个字节而不是4个字节:

 [4][2] // starts at 0 [4][2] // starts at 6 -- the [4] is not properly aligned! [4][2] // starts at 12 

这将是非常糟糕的,因为并非所有体系结构都允许从未对齐的内存地址读取,甚至那些具有(可能非常大,如果在高速缓存行或页面边界上)执行它的性能损失的内存地址。

除了基本性能之外,对齐还可以实现并发性。 C#内存模型保证最多4个字节宽的本机类型的读/写是primefaces的,而.NET具有像Interlocked类这样的primefaces特性。 像这样的primefaces操作归结为CPU指令本身需要对齐的内存访问才能工作。

正确对齐非常重要!

您经常会看到聪明的本地编码人员在布置他们的结构时记住所有这些,将所有字段从最大到最小排序,以便将填充和结构大小保持在最低限度。

上述就是C#学习教程:CLR顺序结构布局:对齐和大小分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—猴子技术宅(www.ssfiction.com)

本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ssfiction.com/ckf/1031701.html

发表评论

邮箱地址不会被公开。 必填项已用*标注