Memory 为什么结构中“[0]字节”的位置很重要?
golang中的Memory 为什么结构中“[0]字节”的位置很重要?,memory,go,struct,padding,sizeof,Memory,Go,Struct,Padding,Sizeof,golang中的[0]字节不应占用任何内存空间。但这两个结构的大小不同 type bar2 struct { A int _ [0]byte } type bar3 struct { _ [0]byte A int } 那么为什么[0]字节的位置在这里很重要呢 顺便说一下,我使用unsafe.Sizeof()方法检查结构大小。参见。原因是“孔”: 孔是编译器添加的未使用的空格,以确保 以下字段或元素相对于起点正确对齐 结构或数组[1]的 例如(数字基于g
[0]字节
不应占用任何内存空间。但这两个结构的大小不同
type bar2 struct {
A int
_ [0]byte
}
type bar3 struct {
_ [0]byte
A int
}
那么为什么[0]字节的位置在这里很重要呢
顺便说一下,我使用unsafe.Sizeof()
方法检查结构大小。参见。原因是“孔”:
孔是编译器添加的未使用的空格,以确保
以下字段或元素相对于起点正确对齐
结构或数组[1]的
例如(数字基于go游乐场使用的任何硬件):
可以使用以下方法验证结构的布局:
- 返回所需的对齐方式
- 计算字段相对于其封闭结构(包括孔)起点的偏移量
[1] 2016年,北卡罗来纳州克尼汉多诺万第354页。围棋编程语言。纽约第一版:艾迪生·韦斯利。这是由于一个棘手的填充
首先,请允许我稍微重命名结构和字段,以便更容易地讨论它们:
type bar1 struct {
A [0]byte
I int
}
type bar2 struct {
I int
A [0]byte
}
当然,这不会改变尺寸和偏移,可以通过以下方式进行验证:
类型为[0]byte
的值的大小为零,因此在bar1
中完全可以不为第一个字段(bar1.a
)保留任何空间,并以0偏移量布置bar1.I
字段
问题是:为什么编译器不能在第二种情况下(使用bar2
)执行相同的操作
字段的地址必须位于为前一个字段保留的内存区域之后。在第一种情况下,第一个字段bar1.A
的大小为0,因此第二个字段的偏移量可能为0,它不会与第一个字段“重叠”
在bar2
的情况下,第二个字段不能有与第一个字段重叠的地址(因此偏移量),因此其偏移量不能小于int
的大小,在32位体系结构的情况下为4字节(在64位体系结构的情况下为8字节)
这似乎还可以。但是既然bar2.A
的大小为零,为什么结构bar2
的大小不能是4字节(或64位拱形中的8字节)
这是因为采用大小为0的字段(和变量)的地址是完全有效的。好吧,那又怎样
在bar2
的情况下,编译器必须插入一个4(或8)字节的填充,否则采用bar2的地址。
字段将指向为bar2
类型的值保留的内存区域之外
例如,不带填充值bar2
的地址可能为0x100
,大小为4,因此为结构值保留的内存的地址范围为0x100。。0x103
。bar2.A
的地址将是0x104
,它位于结构的内存之外。对于此结构的数组(例如x[5]bar2
),如果数组从0x100
开始,则x[0]
的地址将是0x100
,x[0]的地址。A
将是0x104
,后续元素的地址将是x[1]
也将是0x104
,但这是另一个结构值的地址!不酷
为了避免这种情况,编译器会插入一个填充(根据拱的不同,它将是4或8个字节),这样获取bar2.a的地址将不会导致地址超出结构的内存,否则可能会引发问题并导致垃圾收集问题(例如,如果只保留bar2.A
的地址,而不保留结构或指向该结构或其其他字段的另一个指针,则不应对整个结构进行垃圾收集,但由于没有指针指向其内存区域,因此这样做似乎是有效的)。插入的填充将为4(或8)字节,因为
对于结构类型的变量x
:unsafe.Alignof(x)
是unsafe.Alignof(x.f)
的每个字段f
,但至少1
如果是这样,添加一个额外的int
字段将使两个结构的大小相等:
type bar1 struct {
I int
A [0]byte
X int
}
type bar2 struct {
A [0]byte
I int
X int
}
事实上,它们在32位arch上都有8个字节(在64位arch上有16个字节)(请在上尝试):
请参阅相关问题:大小是什么?bar2:8的大小,bar3:4的大小bool
使用内存空间,这与[0]字节
不同。如果将bar2和bar3中的[0]字节
替换为bool
,两个结构将具有相同的大小。这里有一个完整的示例:是,但需要对齐[0]字节为1。您可以使用unsafe.Alignof
检查所需的对齐方式,并使用unsafe.Offsetof
计算字段的偏移量。查看是否打印bool
和[0]的Alignof
和offset
byte
成员,您会发现它们对于两种不同的类型是相同的。因此,这无法解释结构大小的差异。请参阅
bar1 size: 4
bar1.A offset: 0
bar1.I offset: 0
bar2 size: 8
bar2.I offset: 0
bar2.A offset: 4
type bar1 struct {
I int
A [0]byte
X int
}
type bar2 struct {
A [0]byte
I int
X int
}
bar1 size: 8
bar1.I offset: 0
bar1.A offset: 4
bar1.X offset: 4
bar2 size: 8
bar2.A offset: 0
bar2.I offset: 0
bar2.X offset: 4