package main
import (
"fmt"
"unsafe"
)
type A struct {
a bool
b int64
c int
}
type B struct {
b int64
a bool
c int
}
type C struct {
}
func main() {
// output 24
fmt.Println(unsafe.Sizeof(A{}))
// output 16
fmt.Println(unsafe.Sizeof(B{}))
// output 0
fmt.Println(unsafe.Sizeof(C{}))
}
Struct A
和B
具有相同的字段,但如果以不同的顺序指定,则会产生不同的大小。为什么呢?
struct C
的大小为零。系统为a := C{}
分配了多少内存?
感谢。
答案 0 :(得分:11)
<强> TL; DR; (摘要):如果重新排序字段,将使用不同的隐式填充,隐式填充将计入struct
的大小。
请注意,结果取决于目标架构;您发布的结果在GOARCH=386
时适用,但在GOARCH=amd64
时,A{}
和B{}
的大小将为24字节。
结构的字段地址必须对齐,类型int64
的字段地址必须是8字节的倍数。 Spec: Package unsafe
:
计算机体系结构可能要求内存地址对齐;也就是说,对于变量的地址是因子的倍数,变量的类型对齐。函数
Alignof
采用表达任何类型变量的表达式,并以字节为单位返回(变量类型)的对齐方式。
int64
的对齐是8个字节:
fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8
所以在A
的情况下,因为第一个字段是bool
,所以在A.a
之后有一个7字节的隐式填充,因此A.b
类型为int64
可以从一个8的倍数开始。这个(确切需要7字节填充)得到保证,因为struct
本身与8的倍数对齐,因为那是所有领域中规模最大的。请参阅:Spec: Size alignment guarantees:
对于结构类型的变量
x
:unsafe.Alignof(x)
是unsafe.Alignof(x.f)
的每个字段f
的所有值x
中的最大值,但至少1
。
如果B
(如果GOARCH=386
是你的情况),那么在B.a
类型的bool
字段之后只会有一个3字节的隐式填充,因为此字段后跟一个int
类型的字段(大小为4个字节),而不是int64
。
如果int
,GOARCH=386
的对齐为4个字节,GOARCH=amd64
则为8个字节:
fmt.Println(unsafe.Alignof((int(0)))) // Prints 4 if GOARCH=386, and 8 if GOARCH=amd64
使用unsafe.Offsetof()
查找字段的偏移量:
// output 24
a := A{}
fmt.Println(unsafe.Sizeof(a),
unsafe.Offsetof(a.a), unsafe.Offsetof(a.b), unsafe.Offsetof(a.c))
// output 16
b := B{}
fmt.Println(unsafe.Sizeof(b),
unsafe.Offsetof(b.b), unsafe.Offsetof(b.a), unsafe.Offsetof(b.c))
// output 0
fmt.Println(unsafe.Sizeof(C{}))
var i int
fmt.Println(unsafe.Sizeof(i))
如果GOARCH=386
输出(在Go Playground上尝试):
24 0 8 16
16 0 8 12
0
4
输出GOARCH=amd64
:
24 0 8 16
24 0 8 16
0
8
Spec: Size alignment guarantees:
如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零。 两个不同的零大小变量在内存中可能具有相同的地址。
因此规范只是提示使用相同的内存地址但不是必需的。但目前的实施遵循它。也就是说,不会为大小为零的类型的值分配内存,这包括空结构struct{}
和零长度的数组,例如, [0]int
,或其元素大小为零(且任意长度)的数组。
见这个例子:
a := struct{}{}
b := struct{}{}
c := [0]int{}
d := [3]struct{}{}
fmt.Printf("%p %p %p %p %p", &a, &b, &c, &d, &d[2])
输出(在Go Playground上试试):所有地址都相同。
0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c 0x21cd7c
有关一个有趣且相关的主题,请阅读:Dave Cheney: Padding is hard