为什么在C#数据类型中存储开销会产生浪费?

5
在《C# 5.0权威指南》一书的子主题存储开销中,有一条通用注释如下:

enter image description here

现在,我想知道为什么结构体A中的字段会浪费空间?或者说,作者在整个注释中想表达什么意思?

4
数据结构对齐(Data Structure Alignment)是计算机科学中的一个概念,指的是为了提高数据访问效率而进行的内存空间优化。在计算机系统中,数据通常按照特定规则进行排列和布局,以保证 CPU 能够高效地读取和写入内存。这些规则包括数据对齐、填充字节等。数据对齐可以将数据类型的起始位置调整到固定的地址上,使其能够被高效地读取。填充字节则是为了保证不同数据类型之间的对齐,从而避免出现访问错误或性能下降。 - dtb
因为它使用16个字节来存储9个字节的数据。 - H H
1
请注意,“waste”用引号括起来。这种对齐是有原因的,因此是否真正可以将其归类为“浪费”还是很主观的。因为我们肯定不能在这里浪费空间,但是如果不对齐数据,我们就会浪费时间。这是时空权衡的又一个例子。 - jason
这个问题比看起来的要难解释得多。将long对齐到8实际上没有任何意义,32位GC和Jitter只能将结构体的开始对齐到4。因此,long没有任何保证实际上对齐到8。它之所以能正常工作,是因为这些是本机代码使用的对齐规则。这使结构体可按位拷贝,对于互操作速度很重要。本机代码规则受早期32位处理器设计的影响非常大。 - Hans Passant
4个回答

9
每个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------------->

2
你没有解释为什么它“必须”放置在8的倍数地址上。显然,可以单独访问(读取和写入)这15个字节中的任何一个,因此这里还有其他问题(是的,我知道区别在哪里,但这是你的答案)。 - Lasse V. Karlsen
@LasseV.Karlsen:我认为 OP 是在寻求解释给定引用的帮助,而不是寻求其背后的技术理由。这不是我的专业领域,所以如果你认为需要详细说明,请随意发表单独的答案。 - Douglas

5

请注意对齐方式。 Long类型必须位于位置0、8、16等位置...

但是如果我们先看字节,则如下所示:

b-------llllllll

假设b是一个字节,l是一个长整型。减号代表“浪费的空间”。 因此,可以看出这个结构体使用了整整16个字节,但只使用了9个字节,因此有7个字节被浪费了。


4

这个结构体默认的布局方式有两个原因:

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));
}

输出12,表示打包效果更好。

如果您使用 [StructLayout(LayoutKind.Sequential, Pack = 1)],则可以将大小缩小到9


2

它们通常与处理器字边界对齐,以便检索它们是一个简单的单周期操作。否则,CLR必须获取整个地址,并XOR / shift结构字段以引用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接