内存对齐对性能的影响

news/2024/10/18 12:26:07/

计算字节数

在 Go 语言中,可以使用 unsafe.Sizeof 计算出一个数据类型实例需要占用的字节数。

package mainimport ("fmt""unsafe"
)type Args struct {num1 intnum2 int
}type Flag struct {num1 int16num2 int32
}func main() {fmt.Println(unsafe.Sizeof(Args{}))fmt.Println(unsafe.Sizeof(Flag{}))
}

在这里插入图片描述

  1. Args 由 2 个 int 类型的字段构成,在 64位机器上,一个 int 占 8 字节,因此存储一个 Args 实例需要 16 字节。
  2. Flag 由一个 int32 和 一个 int16 的字段构成,成员变量占据的字节数为 4+2 = 6,但是 unsafe.Sizeof 返回的结果为 8 字节,多出来的 2 字节是内存对齐的结果。

因此,一个结构体实例所占据的空间等于各字段占据空间之和,再加上内存对齐的空间大小。

内存对齐

  1. CPU 只从对齐的地址开始加载数据

  2. CPU 读取块的大小是固定的,通常为 B 的 2 的整数幂次

  3. CPU 访问内存时,并不是逐个字节访问,而是以字长(word size)为单位访问。比如 32 位的 CPU ,字长为 4 字节,那么 CPU 访问内存的单位也是 4 字节。

  4. 这么设计的目的,是减少 CPU 访问内存的次数,加大 CPU 访问内存的吞吐量。比如同样读取 8 个字节的数据,一次读取 4 个字节那么只需要读取 2 次。

  5. CPU 始终以字长访问内存,如果不进行内存对齐,很可能增加 CPU 访问内存的次数。

在这里插入图片描述
6. 变量 a、b 各占据 3 字节的空间,内存对齐后,a、b 占据 4 字节空间,CPU 读取 b 变量的值只需要进行一次内存访问。
7. 如果不进行内存对齐,CPU 读取 b 变量的值需要进行 2 次内存访问。第一次访问得到 b 变量的第 1 个字节,第二次访问得到 b 变量的后两个字节。

结论:内存对齐对实现变量的原子性操作也是有好处的,每次内存访问是原子的,如果变量的大小不超过字长,那么内存对齐后,对该变量的访问就是原子的,这个特性在并发场景下至关重要。

对齐系数

unsafe 标准库提供了 Alignof 方法,可以返回一个类型的对齐值,也可以叫做对齐系数或者对齐倍数。

unsafe.Alignof(Args{}) // 8
unsafe.Alignof(Flag{}) // 4
  1. 对于任意类型的变量 x ,unsafe.Alignof(x) 至少为 1。
  2. 对于 struct 结构体类型的变量 x,计算 x 每一个字段 f 的 unsafe.Alignof(x.f),unsafe.Alignof(x) 等于其中的最大值。
  3. 对于 array 数组类型的变量 x,unsafe.Alignof(x) 等于构成数组的元素类型的对齐倍数。
  4. 没有任何字段的空 struct{} 和没有任何元素的 array 占据的内存空间大小为 0,不同的大小为 0 的变量可能指向同一块地址。

struct 内存对齐

type demo1 struct {a int8b int16c int32
}type demo2 struct {a int8c int32b int16
}func main() {fmt.Println(unsafe.Sizeof(demo1{})) // 8fmt.Println(unsafe.Sizeof(demo2{})) // 12
}

demo1:

  1. a 是第一个字段,默认是已经对齐的,从第 0 个位置开始占据 1 字节。
  2. b 是第二个字段,对齐倍数为 2,因此,必须空出 1 个字节,偏移量才是 2 的倍数,从第 2 个位置开始占据 2 字节。
  3. c 是第三个字段,对齐倍数为 4,此时,内存已经是对齐的,从第 4 个位置开始占据 4 字节即可。

因此 demo1 的内存占用为 8 字节。

在这里插入图片描述

demo2:

  1. a 是第一个字段,默认是已经对齐的,从第 0 个位置开始占据 1 字节。
  2. c 是第二个字段,对齐倍数为 4,因此,必须空出 3 个字节,偏移量才是 4 的倍数,从第 4 个位置开始占据 4 字节。
  3. b 是第三个字段,对齐倍数为 2,从第 8 个位置开始占据 2 字节,但最大对齐倍数为4,需要填充2个字节

demo2 的对齐倍数由 c 的对齐倍数决定,也是 4,因此,demo2 的内存占用为 12 字节。

在这里插入图片描述

空结构体

空 struct{} 大小为 0,作为其他 struct 的字段时,一般不需要内存对齐。
但是有一种情况除外:即当 struct{} 作为结构体最后一个字段时,需要内存对齐。


http://www.ppmy.cn/news/623785.html

相关文章

确定你的台式计算机支持的内存类型,如何区分内存类型及查看内存的兼容性

经常会遇到有人想更换内存不知道买什么样的内存,也常遇到人问升级内存要买什么样的内存才兼容,这里给大家分享一下,顺带科普一下。伸手党可以直接跳过看总结: 1、不同代的内存相互是不兼容的。内存可分为DDR1、DDR2、DDR3,这里的1、2、3指的就是第几代内存,这些内存之间相…

内存SPD的介绍和刷新(可以改善内存不兼容的问题)

SPD 简介 SPD是SERIAL PRESENCE DETECT的缩写,中文意思是模组存在的串行检测。也即是通过上面讲的IIC串行接口的EEPROM堆内存插槽中的模组存在的信息检查。这样的话,模组有关的信息都必须纪录在EEPROM中.习惯的,我们把这颗EEPROM IC就称为SPD…

计算机可用内存分配失败,安装内存和实际可用内存不一样什么原因

通常我们安装内存条时候都有显示具体内存,但是有时出现安装内存和实际可用内存不一致?为什么会不一样呢?下面我们一起来看看其中的原因和解决方法。 一、你安装的不是64位Win7系统 Win7 32位只能识别小于4G的内存,所以你有4G内存建议安装win7 64位旗舰…

不兼容问题

1.内存与主板不兼容 内存与主板不兼容的故障较为常见,表现为昨天电脑还用的好好的,可是今天早晨一开机 ,即“嘀嘀”地叫个不停。只有打开机箱,把内存条取下来重新插一下就好了。注意:在拔插 内存条时一定要拔掉主机和…

技巧 | 加装内存不兼容?你少做了很重要的一步

我们在加装台式机内存时,若使用了不合适或兼容性不佳的内存,可能会导致内存以低频率运行,甚至电脑无法开机。 正确的做法 加装内存时,选择QVL清单中的内存可以获得更高的兼容性。 Z790-A吹雪D5 以华硕【ROG STRIX Z790-A GAMIN…

换显卡,还有内存不兼容引发的问题

今天把网上购来的显卡和内存换上机器上了 在坛子上问了一下,才知道不同芯片组的显卡驱动是可以并存在一个系统里面的,而且,换显卡的时候根本不需要调低分辨率,可能是xp自带驱动的原因,今天一问倒真发现好多人在这方面…

【内核隔离开启内存完整性已关闭不兼容的驱动程序驱动程序卸载】

内核隔离开启,内存完整性已关闭,不兼容的驱动程序,驱动程序卸载 问题描述查看不兼容的驱动程序获取不兼容的驱动程序名称删除不兼容的驱动程序打开设备管理器查找不兼容的驱动删除不兼容驱动 重新打开内核隔离,重启电脑&#xff0…

win11内存完整性不兼容驱动程序的五种删除方法

win11内存完整性不兼容的驱动程序怎么删除?win11的驱动不兼容的话,可能会导致软件或者游戏无法正常运行,也会导致Windows安全中心中的内核隔离——内核完整性功能无法开启。那么win11内存完整性不兼容的驱动程序怎么删除呢?下面小…