聊聊go语言中的内存填充

news2024/11/27 8:42:09

写在文章开头

我们都知道数据加载到CPU缓存中可以提升执行性能,所以为了保证每一个结构体中的成员能够完整的被单个CPU核心加载以避免缓存一致性问题而提出内存对齐,这篇文章笔者会从go语言的角度来讨论这个优化机制。

在这里插入图片描述

Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

详解go语言中的内存对齐

内存填充代码示例

我们不妨举个例子,我们现在声明一个Num结构体并通过Sizeof获取其大小:

type Num struct {
	num1 int32
	num2 int32
}

func main() {
	// 打印字节大小
	fmt.Println("Num bytes:", unsafe.Sizeof(Num{}))
}

输出结果为8字节,很明显两个32位的整型变量相加就是8字节:

Num bytes: 8

在这里插入图片描述

我们再来看点神奇的,我们将num1改为int16,再次进行打印,理论上2byte+4byte最终输出应该是6byte

type Num struct {
	num1 int16
	num2 int32
}

func main() {
	// 打印字节大小
	fmt.Println("Num bytes:", unsafe.Sizeof(Num{}))
}


但输出结果确是8byte,这是就是因为底层填充了2byte的内存空间:

Num bytes: 8

详解内存对齐

我们假设Num未进行内存填充的Num 结构体在内存分配为struct-2,在它的地址空间前方有一个struct-1,在多核CPU64位操作系统下,数据都以一个字长即64bit加载,这就很可能导致一个完整的变量存在与不同的CPU核心中。
我们假设一种情况CPU-1操作struct-1,因为字长的原因导致加载数据时把struct-2的数据加载到CPU-1缓存中。同时CPU-2 Cache处理struct-2的业务逻辑,因为MESI协议,导致CPU-1中任何一个改动都会使得CPU-2缓存中的数据变成脏数据,出现缓存一致性问题。

在这里插入图片描述

考虑到这个问题,go语言便在struct-1空间的结尾填充了18bit使得内存空间占满1个字长,保证每一个变量都能通过一个字长的单位读取到:

在这里插入图片描述

内存对齐的工作机制

在进行不同的内存填充的时候,不同类型变量都着不同的对齐系数,例如布尔和int32对应的内存系统为1和4,以下图为例,布尔的对齐系统为1就意味着它的内存空间首地址能被1整除,所以我们分配为0x00,同理因为0x00被布尔占用,所以int32的内存空间地址分配到0x04,基于对齐系数这一计算可以确保了两个变量完整的占用了一个字长,且加载时能够保证每个字长加载的变量都是完整的,从而保证内存原子性:

在这里插入图片描述

	// 不同类型对应的对齐系数
	fmt.Println("类型:", unsafe.Sizeof(false), " 对齐系数:", unsafe.Alignof(false))
	fmt.Println("类型:", unsafe.Sizeof(int32(1)), " 对齐系数:", unsafe.Alignof(int32(1)))
	fmt.Println("类型:", unsafe.Sizeof("hello"), " 对齐系数:", unsafe.Alignof("hello"))

对应输出结果:

类型: 1  对齐系数: 1
类型: 4  对齐系数: 4 
类型: 16  对齐系数: 8

结构体中的内存对齐

我们再来看看结构体中对于内存对齐的使用,我们给出下面这段代码示例:

type Obj struct {
	b   bool
	str string
	num int16
}

func main() {
	//输出其字节数
	fmt.Println(unsafe.Sizeof(Obj{}))
}

这段代码输出结果为32字节,原因很简单,bool为1字节,填充首位。然后string为2字节即(16bit)对应对齐系数为8,所以占用0x080x24的内存空间,最后int16对齐系数为2,于是从0x26开始填充2字节,即占用0x260x28,最后补齐剩余的4个字节空间,由此得出32字节

在这里插入图片描述

这明显因为变量排序不当导致boolstring之间空出了很多的内存空间,所以我们不妨将后面两个变量的顺序调换一下:

type Obj struct {
	b   bool
	num int16
	str string
}

func main() {
	fmt.Println(unsafe.Sizeof(Obj{}))
}

最终输出结果变为24字节,因为int16对齐系统为2,所以bool之后空1格就可以完成对齐,随后移动4格保证字符串类型对齐,由此算出总空间为24字节,确保boolint161个字长(64bit),然后字符串用2个字长完成加载:

在这里插入图片描述

空结构体内存对齐问题

基于上述的例子,我们在结构体末尾加上1个空结构体:

type Obj struct {
	b   bool
	num int16
	str string
	i   struct{}
}

func main() {
	//输出其字节数
	fmt.Println(unsafe.Sizeof(Obj{}))
}

最终输出结果为32,我们都知道空值默认都用zero-base,为了保证空结构体的地址空间不被其他成员错误利用,go语言会针对这种情况对结构体尾部进行一个内存填充,确保地址空间大小为32字节(字长的整数倍)

在这里插入图片描述

小结

本文通过几个简单的示例结合图解介绍了go语言如何通过内存填充的方式解决内存原子性以及缓存一致性问题,我们来简单小结一下内存填充的几个要点:

  1. 通过对齐系数决定变量首地址值。
  2. 空结构体结尾需要填充空间避免地址复用异常。
  3. 整个结构体填充完成后需要保证是字长(64bit)的整数倍。

我是 sharkchiliCSDN Java 领域博客专家开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

参考

CPU 缓存一致性:https://xiaolincoding.com/os/1_hardware/cpu_mesi.html#cpu-cache-的数据写入

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1604029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Springboot+Vue的Java项目-网上点餐系统开发实战(附演示视频+源码+LW)

大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &am…

杀鸡焉用牛刀,用unity3D开发数字孪生是大材小用吗?

"杀鸡焉用牛刀"这句话的意思是指使用过于强大或不适合的工具来完成一个简单的任务。而用Unity3D开发数字孪生并不一定是大材小用。 Unity3D是一款功能强大的游戏开发引擎,它可以用于开发各种类型的游戏和交互应用程序。数字孪生是一种基于现实世界对象的虚…

网络靶场实战-PE 自注入

默认的 Windows API 函数(LoadLibrary、LoadLibraryEx)只能加载文件系统中的外部库,无法直接从内存中加载 DLL,并且无法正确地加载 EXE。有时候,确实需要这种功能(例如,不想分发大量文件或者想增…

Redis入门到通关之解决Redis缓存一致性问题

文章目录 ☃️概述☃️数据库和缓存不一致采用什么方案☃️代码实现☃️其他 ☃️概述 由于我们的 缓存的数据源来自于数据库, 而数据库的 数据是会发生变化的, 因此,如果当数据库中 数据发生变化,而缓存却没有同步, 此时就会有 一致性问题存在, 其后果是: 用户使用缓存中的过…

Python 数据结构和算法实用指南(二)

原文:zh.annas-archive.org/md5/66ae3d5970b9b38c5ad770b42fec806d 译者:飞龙 协议:CC BY-NC-SA 4.0 第四章:列表和指针结构 我们已经在 Python 中讨论了列表,它们方便而强大。通常情况下,我们使用 Python…

【C语言__基础概念__复习篇8】

目录 前言 一、C语言是什么 二、C语言的发展历史 三、编译器的选择 3.1 编译和链接 3.2 编译器的对比 3.3 VS如何使用 四、main函数 五、关键字 六、字符和ASCII编码 七、字符串和\0 八、转义字符 九、注释 十、数据类型 10.1 数据类型的介绍 10.2 数据类型大小的计…

有哪些网站设计教程

网站设计教程是帮助人们学习如何设计和开发网站的资源,它们提供了从基础知识到高级技巧的全方位指导。无论您是初学者还是经验丰富的开发者,都可以从这些教程中获益。下面是一些广受欢迎的网站设计教程,它们涵盖了各种技术和工具:…

Linux之进程控制进程终止进程等待进程的程序替换替换函数实现简易shell

文章目录 一、进程创建1.1 fork的使用 二、进程终止2.1 终止是在做什么?2.2 终止的3种情况&&退出码的理解2.3 进程常见退出方法 三、进程等待3.1 为什么要进行进程等待?3.2 取子进程退出信息status3.3 宏WIFEXITED和WEXITSTATUS(获取…

【C++题解】1345. 玫瑰花圃

问题:1345. 玫瑰花圃 类型:基本运算、小数运算 题目描述: 有一块nn(n≥5,且 n 是奇数)的红玫瑰花圃,由 nn 个小正方形花圃组成,现要求在花圃中最中间的一行、最中间的一列以及 4 个…

SpringBoot多数据源基于mybatis插件(三)

SpringBoot多数据源基于mybatis插件(三) 1.主要思路2.具体实现 1.主要思路 MyBatis的插件机制允许你在MyBatis的四大对象(Executor、StatementHandler、ParameterHandler和ResultSetHandler)的方法执行前后进行拦截,并…

考察自动化立体库应注意的几点

导语 大家好,我是智能仓储物流技术研习社的社长,老K。专注分享智能仓储物流技术、智能制造等内容。 整版PPT和更多学习资料,请球友到知识星球 【智能仓储物流技术研习社】自行下载 考察自动化立体仓库的关键因素: 仓库容量&#x…

linux 中ifconfig 无法使用

1、先看问题 2、搜索 ifconfig 命令,看下该命令在哪 yum search ifconfig 可以看到ifconfig命令在 net-tools.x86_64这个包里。 3、下面开始安装,执行下面的命令 yum install net-tools.x86_64 4、查看是否安装成功 ifconfig 看到上面的ip就说明可以用了…

光网络中的低偏SOA与无源波导单片集成

----翻译自Aref Rasoulzadeh Zali等人2021年撰写的文章 摘要 在光通信系统中,非常需要可以通过简单工艺与无源光路单片集成的低偏振相关半导体光放大器(SOA)。然而,尽管已经报道了几种SOA,但在InP平台中将偏振无关的体…

ROS学习笔记(12)AEB和TTC的实现

0.前提 在自动驾驶领域有许多关于驾驶安全的措施AEB和TTC就是为了驾驶安全而设计出来的。在这篇文章中我会讲解我对AEB和TTC算法的一些理解。本期ROS学习笔记同时也是ros竞速小车的学习笔记,我会将我的部分代码拿出来进行讲解,让大家更好的理解ttc和aeb…

html接入高德地图

1.申请key key申请地址&#xff1a;https://console.amap.com/dev/key/app 官方文档 https://lbs.amap.com/api/javascript-api-v2/summary 2.html接入示例 需要将YOUR_KEY替换成自己的key <!doctype html> <html> <head><meta charset"utf-…

未来计算机的发展趋势是什么?

未来计算机的发展趋势是多方面的,涵盖了硬件、软件、体系结构以及计算范式等多个层面。以下是一些预期的趋势: 1. 量子计算: 随着量子理论的不断成熟和技术的进步,量子计算机将可能解决传统计算机难以处理的问题,比如药物发现、材料科学、复杂系统模拟等领域。量子计算的…

VMWare Ubuntu压缩虚拟磁盘

VMWare中ubuntu会越用越大&#xff0c;直到占满预分配的空间 即使系统里没有那么多东西 命令清理 开机->open Terminal sudo vmware-toolbox-cmd disk shrink /关机-> 编辑虚拟机设置->硬盘->碎片整理&压缩 磁盘应用 开机->disk usage analyzer(应用) …

Java面试:算法常用面试题汇总

1.说一下什么是二分法&#xff1f;使用二分法时需要注意什么&#xff1f;如何用代码实现&#xff1f; 二分法查找&#xff08;Binary Search&#xff09;也称折半查找&#xff0c;是指当每次查询时&#xff0c;将数据分为前后两部分&#xff0c;再用中值和待搜索的值进行比较&…

格灵深瞳,实现核心能力高强度保护与灵活交付

格灵深瞳&#xff0c;AI领域的领先企业&#xff0c;借助泰雷兹圣天诺技术&#xff0c;实现核心能力高强度保护与灵活交付&#xff0c;引领行业风向&#xff0c;安策信息助力AI行业企业实现产品核心能力保护、销售模式创新以及软件产品的灵活交付。 格灵深瞳&#xff0c;AI领域的…

生成人工智能体:人类行为的交互式模拟论文与源码架构解析(2)——架构分析 - 核心思想环境搭建技术选型

4.架构分析 4.1.核心思想 超越一阶提示&#xff0c;通过增加静态知识库和信息检索方案或简单的总结方案来扩展语言模型。 将这些想法扩展到构建一个代理架构&#xff0c;该架构处理检索&#xff0c;其中过去的经验在每个时步动态更新&#xff0c;并混合与npc当前上下文和计划…