网站地图怎么做_,有什么网站可以免费搭建网址,温州市住房和城乡建设局,优惠网站建设什么是内存对齐
在访问特定类型变量的时候通常在特定的内存地址访问#xff0c;这就需要对这些数据在内存中存放的位置有限制#xff0c;各种类型数据按照一定的规则在空间上排列#xff0c;而不是顺序的一个接一个的排放#xff0c;这就是对齐。
内存对齐是编译器的管辖…什么是内存对齐
在访问特定类型变量的时候通常在特定的内存地址访问这就需要对这些数据在内存中存放的位置有限制各种类型数据按照一定的规则在空间上排列而不是顺序的一个接一个的排放这就是对齐。
内存对齐是编译器的管辖范围。表现为编译器为程序中的每个“数据单元”安排在适当的位置上。
为什么需要内存对齐 有些CPU可以访问任意地址上的任意数据而有些CPU只能在特定地址访问数据因此不同硬件平台具有差异性这样的代码就不具有移植性如果在编译时将分配的内存进行对齐这就具有平台可以移植性了。 CPU 访问内存时并不是逐个字节访问而是以字长word size为单位访问例如 32位的CPU 字长是4字节64位的是8字节。如果变量的地址没有对齐可能需要多次访问才能完整读取到变量内容而对齐后可能就只需要一次内存访问因此内存对齐可以减少CPU访问内存的次数加大CPU访问内存的吞吐量。
假设每次访问的步长为4个字节如果未经过内存对齐获取b的数据需要进行两次内存访问最后再进行数据整理得到b的完整数据
如果经过内存对齐一次内存访问就能得到b的完整数据减少了一次内存访问 golang中unsafe.AlignOf()函数
unsafe.AlignOf(x) 方法的返回值是 m当变量进行内存对齐时需要保证分配到 x 的内存地址能够整除 m。因此可以通过这个方法确定变量x 在内存对齐时的地址
对于任意类型的变量 x unsafe.Alignof(x) 至少为 1。对于 struct 结构体类型的变量 x计算 x 每一个字段 f 的 unsafe.Alignof(x.f)unsafe.Alignof(x) 等于其中的最大值。对于 array 数组类型的变量xunsafe.Alignof(x) 等于构成数组的元素类型的对齐倍数。
对于系统内置基础类型变量 x unsafe.Alignof(x) 的返回值就是 min(字长/8unsafe.Sizeof(x))即计算机字长与类型占用内存的较小值
func main() {fmt.Println(unsafe.Alignof(int(1))) // 1 -- min(8,1)fmt.Println(unsafe.Alignof(int32(1))) // 4 -- min (8,4)fmt.Println(unsafe.Alignof(int64(1))) // 8 -- min (8,8)fmt.Println(unsafe.Alignof(complex128(1))) // 8 -- min(8,16)
} 内存对齐规则
成员对齐规则
针对一个基础类型变量如果 unsafe.AlignOf() 返回的值是 m那么该变量的地址需要 被m整除 如果当前地址不能整除填充空白字节直至可以整除。
整体对齐规则
针对一个结构体如果 unsafe.AlignOf() 返回值是 m需要保证该结构体整体内存占用是 m的整数倍如果当前不是整数倍需要在后面填充空白字节。
通过内存对齐后就可以在保证在访问一个变量地址时
如果该变量占用内存小于字长保证一次访问就能得到数据如果该变量占用内存大于字长保证第一次内存访问的首地址是该变量的首地址。
eg
type A struct {a int32b int64c int32
}func main() {fmt.Println(unsafe.Sizeof(A{1, 1, 1})) // 24
}
第一个字段是 int32 类型unsafe.Sizeof(int32(1))4内存占用为4个字节同时unsafe.Alignof(int32(1)) 4内存对齐需保证变量首地址可以被4整除我们假设地址从0开始0可以被4整除 2. 第二个字段是 int64 类型unsafe.Sizeof(int64(1)) 8内存占用为 8 个字节同unsafe.Alignof(int64(1)) 8需保证变量放置首地址可以被8整除当前地址为4距离4最近的且可以被8整除的地址为8因此需要添加四个空白字节从8开始放置 第三个字段是 int32 类型unsafe.Sizeof(int32(1))4内存占用为4个字节同时unsafe.Alignof(int32(1)) 4内存对齐需保证变量首地址可以被4整除当前地址为1616可以被4整除 所有成员对齐都已经完成现在我们需要看一下整体对齐规则unsafe.Alignof(A{}) 8即三个变量成员的最大值内存对齐需要保证该结构体的内存占用是 8 的整数倍当前内存占用是 20个字节因此需要再补充4个字节 最终该结构体的内存占用为 24字节。
type B struct {a int32b int32c int64
}func main() {fmt.Println(unsafe.Sizeof(B{1, 1, 1})) // 16
}第一个字段是 int32 类型unsafe.Sizeof(int32(1))4内存占用为4个字节同时unsafe.Alignof(int32(1)) 4内存对齐需保证变量首地址可以被4整除我们假设地址从0开始0可以被4整除 第二个字段是 int32 类型unsafe.Sizeof(int32(1))4内存占用为4个字节同时unsafe.Alignof(int32(1)) 4内存对齐需保证变量首地址可以被4整除当前地址为44可以被4整除 第三个字段是 int64 类型unsafe.Sizeof(int64(1))8内存占用为8个字节同时unsafe.Alignof(int64(1)) 8内存对齐需保证变量首地址可以被8整除当前地址为88可以被8整除 所有成员对齐都已经完成现在我们需要看一下整体对齐规则unsafe.Alignof(B{}) 8即三个变量成员的最大值内存对齐需要保证该结构体的内存占用是 8 的整数倍当前内存占用是 16个字节已经符合规则最终该结构体的内存占用为 16个字节。
空结构体对齐规则
如果空结构体作为结构体的内置字段当变量位于结构体的前面和中间时不会占用内存当该变量位于结构体的末尾位置时需要进行内存对齐内存占用大小和前一个变量的大小保持一致。
type C struct {a struct{}b int64c int64
}type D struct {a int64b struct{}c int64
}type E struct {a int64b int64c struct{}
}type F struct {a int32b int32c struct{}
}func main() {fmt.Println(unsafe.Sizeof(C{})) // 16fmt.Println(unsafe.Sizeof(D{})) // 16fmt.Println(unsafe.Sizeof(E{})) // 24fmt.Println(unsafe.Sizeof(F{})) // 12
}
参考https://juejin.cn/post/7077833959047954463