在子主题Storage Overhead (on Chapter) - C# 5.0 in a Nutshell book -有这个一般说明说:
现在,我想知道为什么 struct A中的字段会浪费空间?或者,作者对整个笔记的观点是什么?
每个byte
字段占用 1 个字节,而每个long
字段占用 8 个字节。这意味着,虽然b
可以放置在内存中的任何位置,但l
需要放置在 8 的倍数的地址。它不能放置在地址0
,因为它已经被b
;占用。因此,它必须放在下一个可用的 8 倍数处,即8
,导致 7 个字节的中间空间被浪费。
---------------------------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---------------------------------------------------------------------------------
<--b-> <------------------l-------------------->
<--------------waste------------->
只看对齐。Long 必须在位置 0, 8, 16,...
但是如果我们首先有字节,它看起来像这样:
b-------llllllll
用 b 蜂鸣字节 b 和 l 蜂鸣长 l。- 是“浪费的空间”所以你可以看到结构使用了整个 16 个字节,但只使用了 9 个字节,因此浪费了 7 个字节
结构的这种默认设置有两个原因:
1)性能,正如其他人已经解释的那样。将字段成员放置为其大小的倍数允许更快的传输。
2) 与大多数 C/C++ 编译器的默认值相同。这使得与 C/C++(包括所有 Windows API)的互操作更容易一些。
请注意,如果您不需要编组结构,您可以使用[StructLayout(LayoutKind.Auto)]
:
[StructLayout(LayoutKind.Auto)]
struct A
{
byte b;
long l;
}
有了它,下面的代码
unsafe
{
Console.WriteLine(sizeof(A));
}
prints 12
,这表明更好的包装。
如果您使用[StructLayout(LayoutKind.Sequential, Pack = 1)]
,您可以将尺寸缩小到9
.
它们通常在处理器字边界处对齐,因此检索它们是一个简单的单周期操作。否则,CLR 将不得不获取整个地址,并对结构字段进行异或/移位以引用它。