Memory 如果字段顺序不同,则结构的大小也不同
结构Memory 如果字段顺序不同,则结构的大小也不同,memory,struct,go,padding,sizeof,Memory,Struct,Go,Padding,Sizeof,结构A和B具有相同的字段,但如果按不同的顺序指定,则会导致不同的大小。为什么? 结构C的大小为零。系统为a:=C{}分配了多少内存 谢谢。1。结构尺寸 TL;博士(摘要):如果对字段进行重新排序,将使用不同的隐式填充,并且隐式填充将计入结构的大小 注意,结果取决于目标体系结构;当GOARCH=386时,您发布的结果适用,但当GOARCH=amd64时,A{}和B{}的大小都将为24字节 结构的字段地址必须对齐,类型为int64的字段地址必须是8字节的倍数 计算机体系结构可能需要对齐内存地址;也就
A
和B
具有相同的字段,但如果按不同的顺序指定,则会导致不同的大小。为什么?
C
的大小为零。系统为a:=C{}
分配了多少内存GOARCH=386
时,您发布的结果适用,但当GOARCH=amd64
时,A{}
和B{}
的大小都将为24字节
结构的字段地址必须对齐,类型为int64
的字段地址必须是8字节的倍数
计算机体系结构可能需要对齐内存地址;也就是说,如果变量的地址是因子的倍数,则变量的类型的对齐方式。函数Alignof
采用表示任何类型变量的表达式,并以字节为单位返回(变量类型)的对齐方式
int64的对齐长度为8字节:
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{}))
}
因此,在A
的情况下,由于第一个字段是bool
,因此A.A
之后有一个7字节的隐式填充,因此A.b
类型为int64
的地址可以从8的倍数开始。这(需要精确的7字节填充)是有保证的,因为结构本身与地址对齐,地址是8的倍数,因为这是所有字段的最大大小。见:
对于结构类型的变量x
:unsafe.Alignof(x)
是unsafe.Alignof(x.f)
的每个字段f
,但至少1
在B
的情况下(如果GOARCH=386
这是您的情况),类型为bool
的B.a
字段后面将只有一个3字节的隐式填充,因为该字段后面是int
类型的字段(大小为4字节),而不是int64
如果GOARCH=386
,int
的对齐长度为4个字节,如果GOARCH=amd64
,对齐长度为8个字节:
fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8
24 0 8 16
16 0 8 12
0
4
用于查找字段的偏移量:
fmt.Println(unsafe.Alignof((int(0)))) // Prints 4 if GOARCH=386, and 8 if GOARCH=amd64
如果GOARCH=386,则输出(请在上尝试):
如果GOARCH=amd64,则输出:
fmt.Println(unsafe.Alignof((int64(0)))) // Prints 8
24 0 8 16
16 0 8 12
0
4
2.零尺寸值
如果结构或数组类型不包含大小大于零的字段(或元素),则其大小为零两个不同的零大小变量在内存中可能具有相同的地址。
因此,规范只是给出了使用相同内存地址的提示,但这不是一个要求。但目前的实现遵循这一原则。也就是说,不会为大小为零的类型的值分配内存,这包括空结构struct{}
和长度为零的数组,例如[0]int
,或元素大小为零(且具有任意长度)的数组
请参见此示例:
24 0 8 16
24 0 8 16
0
8
输出(在上尝试):所有地址都相同
a := struct{}{}
b := struct{}{}
c := [0]int{}
d := [3]struct{}{}
fmt.Printf("%p %p %p %p %p", &a, &b, &c, &d, &d[2])
有关有趣且相关的主题,请阅读:2。是否需要为元数据分配一些内存,如type info.structs不包含type info(并且除了字段之外没有大小开销),这都由编译器处理。但是,接口包含类型和值。