Golang学习之结构体和内存对齐、map设计思路

news2025/1/14 11:58:40

Golang学习之结构体和内存对齐、map设计思路

  • 结构体和内存对齐
    • 内存对齐
    • 如何确定一个结构体的对其边界
  • map设计思路
    • 哈希表与扩容
    • bmap的结构
    • 练习
    • map扩容规则

结构体和内存对齐

  • cpu要想从内存读取数据,需要通过地址总线,把地址传输给内存,内存准备好数据,输出到数据总线,交给CPU。
  • 如果地址总线只有8根,那这个地址就只有8位,可以表示256个地址,因为表示不了更多的地址就用不了更大的内存。
  • 所以256就是8根地址总线最大的寻址空间,要使用更大的内存,就要有更宽的地址总线。
  • 在这里插入图片描述
  • 每次操作一字节太慢,那就加宽数据总线。
  • 要每次操作4字节,就要至少32位数据总线。8字节64位。每次操作的字节数就是机器字长。
  • 逻辑上的内存:可以访问任意地址并将其输出到总线。
    在这里插入图片描述
  • 实际上为了实现更高的访问效率,典型的内存布局。
  • 一个内存条的一面是一个Rabk,一个Chip包括8个Banks,到Banks就可以通过选择行和列来定位一个地址。
    在这里插入图片描述
  • 非逻辑上连续的存在,但能共用一个地址,各自选择同一个位置的一个字节,再组合起来,作为我们逻辑上认为的连续8个字节。
  • 通过这样的并行操作,提高了内存访问效率。
  • 但这种方式地址必须是8的倍数,
    在这里插入图片描述
  • 不能在一次操作中被同一个地址选中,这样的地址是不能用的。硬件不支持。
    在这里插入图片描述
  • 之所以有些cpu能支持访问任意地址,是因为其多做了许多处理。
  • 例如,想从1开始读8字节的数据,CPU会分两次读,第一次从0到7,但只取后7字节,第二次从8到15,但只取1字节。拼接获得所需数据,但这样做会影响性能。
    在这里插入图片描述

内存对齐

  • 编译器会把各种类型的数据安排到合适的地址,并占用合适的长度,这就是内存对齐。
  • 每种类型的对齐值就是它的对其边界。
  • 内存对齐要求数据存储地址以及占用的字节数都要是它对齐边界的倍数,所以int32不能从2开始,要从4开始。
    在这里插入图片描述
  • 如何确定每种类型的对应边界?这与平台有关
    在这里插入图片描述
  • 被Go语言成为寄存器宽度的这个值,可以理解为机器字长,也是平台对应的最大对齐边界。
  • 而数据类型的对齐边界是取类型大小与平台最大对齐边界中较小的那个
    在这里插入图片描述
    在这里插入图片描述
  • 为何不统一平台最大对齐边界
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 这是小于最大对齐边界的情况
  • 假设要在32位平台存储一个Int64类型的数据,选择4,减少浪费,提高性能。

如何确定一个结构体的对其边界

  • 首先确定每个成员的对齐边界,然后取其中最大的,这就是结构体类型的对齐边界。
    在这里插入图片描述
    在这里插入图片描述
  • 结构体整体占用字节数需要是类型对齐边界的倍数,不够的话要向后扩张,所以要扩充到相对地址23这里。
  • 最终,结构体类型的大小就是24字节。
    在这里插入图片描述
  • 只有每个结构体的大小是对齐值的整数倍,才能保证数组里每一个都是内存对齐的。
    在这里插入图片描述

map设计思路

哈希表与扩容

  • 哈希表通常会有一堆桶来存储键值对。
  • 若要利用哈希值从m个桶中选择一个,桶的编号区间为[0,m-1]
  • 方法一:取模法,得到桶编号
  • 方法二:与运算法,
  • 要限制桶的个数m必须是2的整数次幂,否则将出现某些桶绝对不会被选中。
    在这里插入图片描述
  • 如果又有新的键值对选择了该桶,就是发生了哈希冲突,遍历桶找到key相等的桶。(开放地址法)
  • 冲突时,在它后面链一个新桶存储这个键值对,会顺着链表往后查找(拉链法)
  • 哈希冲突的发生会影响哈希表的读写效率,选择散列均匀的哈希函数可以减少哈希冲突的发生。适时的对哈希表进行扩容也是保障读写效率的有效手段。
  • 通常会把存储键值对的数目与桶的数目的比值,作为是否需要扩容的判断依据,这个比值被称为“负载因子”。需要扩容时就要分配更多的桶。
    在这里插入图片描述
  • 需要在扩容时,先分配足够多的新桶,然后用一个字段记录旧桶的位置,再增加一个字段记录旧桶迁移的进度,例如记录下一个要迁移的旧桶编号。
  • 渐进式扩容:在哈希表每次读写操作时,如果检测到当前处于扩容阶段,就完成一部分键值对迁移任务,直到所有的旧桶迁移完成,旧桶不再使用,才算真正完成一次哈希表的扩容,像这样把键值对迁移的时间分摊到多次哈希表操作中的方式,就是渐进式扩容。
  • 可以避免一次性扩容带来的性能瞬时抖动。
    在这里插入图片描述
  • Go语言中map类型的底层实现就是哈希表
  • map类型的变量本质上是一个指针,指向hmap的结构体。
    在这里插入图片描述
  • count记录已经存储的键值对数目
  • B记录桶的数目是2的多少次幂,因为这里选择桶时用的是与运算的方法。
  • buckets记录桶在哪儿
  • oldbuckets用于在扩容阶段保存旧桶在哪儿
  • nevacuate记录渐进式扩容阶段下一个要迁移的旧桶编号
    在这里插入图片描述

bmap的结构

  • 为了使结构更紧密,含八个键值对在这里插入图片描述
  • 每个tophash都是对应哈希值的高8位
  • 最后为一个bmap型指针,指向一个溢出桶,溢出桶的内存布局与“常规桶”相同,是为了减少扩容次数而引入的。
  • 当一个桶存满了,还有可用的溢出桶时,就会在桶后面链一个溢出桶,继续往这里存。
    在这里插入图片描述
  • 实际上,如果哈希表要分配的桶的数目大于2^4,就认为使用到溢出桶的几率较大,就会预分配
  • 2^(B-4)个溢出桶备用。
    *这些溢出桶与常规桶在内存中是连续的,只是前2^B个用作常规桶,后面的用作溢出桶。
    在这里插入图片描述
  • hmap结构体最后有一个extra字段,指向一个mapextra结构体,里面记录的是溢出桶相关的信息。
  • nextoverflow指向下一个空闲溢出桶;
  • overflow是一个slice,记录目前已经被使用的溢出桶的地址
    在这里插入图片描述
  • 假如编号为2的桶存满了,就会在后面链一个溢出桶,nextoverflow指向下一个空闲桶,noverflow记录使用的溢出桶数量,oldoverflow用于在扩容阶段存储旧桶用到的那些溢出桶的地址。
  • 在这里插入图片描述

练习

  • key和value都是string类型,所以64位下每个key和value都占用16字节
  • 取k1哈希值的高8位存在tophash
  • 字符串内容为k1,占用字节数目为2,value同理。(16个bytes,8ptr,4len,4cap)
    在这里插入图片描述
  • 如果把这个桶存满,这个哈希表是会创建溢出桶还是会发生扩容呢

map扩容规则

  • Go语言map的默认负载因子是6.5,超过这个数就会出发翻倍扩容,分配新桶的数目是旧桶的两倍,
    在这里插入图片描述
  • 例如:如果旧桶数量为4,新桶数量就是8
  • 如果一个哈希值选择0号旧桶,那么哈希值的二进制低两位一定为0。
    在这里插入图片描述
  • 选择新桶的结果只有两种,取决于哈希值的第三位是0还是1,如果第三位为0,则选择编号为0的新桶;如果第三位为1,则选择编号为4的新桶,因为桶的数量一定是2的整数次幂。
  • 在这里插入图片描述
  • 在这里插入图片描述
    所以,无论容量为多少,翻倍扩容后,每个旧桶都会按照这样的规律,分流到两个新桶中,
    在这里插入图片描述
  • 如果负载因子没有超标,但是使用的溢出桶较多,也会触发扩容,但为等量扩容
    在这里插入图片描述
    等量扩容就是创建和旧桶数目一样多的新桶,然后把原来的键值对迁移到新桶中。
    这种情况出现在有很多键值对被删除的情况,等量扩容的方式,使键值对排列的更加紧凑,从而减少溢出桶的使用
  • 在这里插入图片描述

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

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

相关文章

【ONE·Linux || 地址空间与进程控制(一)】

总言 进程地址空间和进程控制相关介绍。 文章目录 总言1、进程地址空间1.1、程序地址空间初识1.1.1、介绍程序地址空间划分及地址空间初步验证1.1.2、地址空间再次综述演示1.1.3、两个补充问题: 1.2、地址空间是什么1.2.1、阶段认识一:故事引入1.2.2、阶…

redis浅析

一 什么是NoSQL? Nosql not only sql(不仅仅是SQL) 关系型数据库:列行,同一个表下数据的结构是一样的。 非关系型数据库:数据存储没有固定的格式,并且可以进行横向扩展。 NoSQL泛指非关系…

论文笔记:AugGPT: Leveraging ChatGPT for Text Data Augmentation

AugGPT:利用 ChatGPT 进行文本数据增强 摘要1 介绍2 相关工作2.1 数据增强2.2 小样本学习2.3 超大型语言模型2.4 ChatGPT:现在与未来 3 数据集3.1 亚马逊数据集3.2 症状数据集3.3 PubMed20k数据集 4 方法4.2 使用 ChatGPT 进行数据增强4.3 小样本文本分类…

Vue3通透教程【十五】补充TS开发环境搭建问题

文章目录 🌟 写在前面🌟 Node中搭建TS开发环境🌟 验证环境🌟 写在最后 🌟 写在前面 专栏介绍: 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章,应粉丝要求开始更新 Vue3 的相关技术文章&#…

【运维】 第02讲(上):企业 Nginx 高性能优化配置实战总结

本课时讲解关于 Nginx 配置优化的内容,相信对于 Nginx 你一定并不陌生,它是一款轻量级的开源 Web 服务及代理程序。在 Nginx 出现之前市场上主流两款 Web 服务,一款是 Windows 系统上的 IIS,另外一款是 Linux 系统上的 Apache。而…

c++11 标准模板(STL)(std::basic_istream)(七)

定义于头文件 <istream>template< class CharT, class Traits std::char_traits<CharT> > class basic_istream : virtual public std::basic_ios<CharT, Traits> 类模板 basic_istream 提供字符流上的高层输入支持。受支持操作包含带格式的…

​“你的期望薪资是多少?” Hr现身说法,以退为进多杀2k

面试是初见1小时就要相互了解优缺点的过程&#xff0c;在你问我答的交锋中如何不露声色、不卑不亢的展现自己&#xff0c;通过以下几个常见问题的拆解&#xff0c;你会得到答案的~ 1.你的期望薪资是多少&#xff1f; 菜鸟的回答:假设上家公司是10K&#xff0c;一般人会说我想…

命令行系列:windows cmd官方文档

官方文档 和java开发、Android开发一样。cmd也有官方文档&#xff1a; https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/windows-commands 如下图&#xff0c;我们可以看到经典的cd,clean命令。 cd命令的全程是什么&#xff1f; cd命令…

基于51单片机的红外测温系统的设计与实现

功能框图 功能描述 本设计以STC89C52单片机为核心控制器&#xff0c;加上其他的模块一起组成非接触人体红外测温的整个系统&#xff0c;其中包含中控部分、输入部分和输出部分。中控部分采用了STC89C52单片机&#xff0c;其主要作用是获取输入部分数据&#xff0c;经过内部处理…

基于SpringBoot+vue的校园闲置物品交易网站设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

【测试开发】软件测试的常用概念

目录 一. 软件测试的生命周期 1. 需求分析 2. 测试计划 3. 测试设计&#xff0c;测试开发 4. 测试执行 5. 测试评估 ​编辑 二. 软件的生命周期 1. 需求分析 2. 计划阶段 3. 设计阶段 4. 编码阶段 5. 测试阶段 6. 运行维护 三. 如何描述一个BUG 1. 发现问题…

Mac 谷歌浏览器选中查看悬浮出现的元素样式

Mac 谷歌浏览选中查看悬浮出现的元素样式 1. Mac 暂停脚本执行快捷键 command \或F8 2.以斗鱼主站下载悬浮面板为例 3. 操作步骤 &#xff08;1&#xff09;打开控制台&#xff0c;选中源代码 &#xff08;2&#xff09;鼠标选中下载&#xff0c;让面板悬浮出来 &#xf…

网络安全面试题

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…

Linux命令----modprobe命令详解

【原文链接】Linux命令----modprobe命令详解 一、modprobe命令的作用 加载内核模块&#xff1a; 使用modprobe命令可以加载指定的内核模块到运行中的内核中。加载内核模块可以在运行时添加新的功能、驱动程序或修改内核行为。 解决模块依赖关系&#xff1a; modprobe命令可以…

机器学习学习笔记——第二章:模型评估与选择

机器学习 机器学习学习笔记——第二章&#xff1a;模型评估与选择 文章目录 机器学习一、经验误差与过拟合1.1、经验误差与泛化误差1.2、过拟合与欠拟合 二、 三个问题三、评估方法3.1、留出法&#xff08;hold-out&#xff09;3.2、k折-交叉验证法&#xff08;k-fold cross v…

银河麒麟系统无法进入桌面拷贝备份文件

最近使用VMWare搭建银河麒麟系统升级后&#xff0c;无法进入桌面&#xff0c;而是进入tty1界面 这个时候如何想导出里面的文件就可以用文件共享的方式右键到虚拟机设置-选项&#xff0c;如图所示 选择一个共享目录 如d盘vm目录 登录tty1账号密码 ls列出文件 如图进行文件拷贝…

.NetCore录屏生成Gif动图程序(Form)的开发过程[代码已上传GitCode]

&#x1f32e;.NetCore录屏生成Gif动图程序(Form)的开发过程 前言: 开发环境&#xff1a;.NetCore3.1 GitCode地址&#xff1a;罗马苏丹默罕默德 / RecordDesktopGif GitCode FrameWork版本地址&#xff1a;尚未同步功能 实现功能 选中屏幕的一块矩形区域按照设置的参数录制…

Qt中QMainWindow的相关介绍

目录 菜单栏 工具栏 状态栏&#xff1a; 停靠窗口&#xff1a; QMainWindow 是标准基础窗口中结构最复杂的窗口&#xff0c;其组成如下: 提供了菜单栏 , 工具栏 , 状态栏 , 停靠窗口 菜单栏&#xff1a;只能有一个&#xff0c;位于窗口的最上方 工具栏&#xff1a;可以有多…

《爱的教育》超全思维导图

思维导图是帮助理解和记忆的高效生产力工具&#xff01; 思维导图以图形的形式表达信息&#xff0c;可视化和关联性&#xff0c;可以更好的激发创作和想象力。 在思维导图中&#xff0c;我们使用简洁的关键词或短语来表达思想&#xff0c;而不是完整的句子或段落。可以帮助我们…

MAYA鲨鱼的绑定

最后一个柚有问题 轴向正确的旋转&#xff0c;成C型 弄乱了 W整体移动 D单个移动 X轴没指向下一个关节 控制器创建 根控制器 控制器很好匹配关节 建组 出来了&#xff0c;控制器位置还在 确保旋转关节是0 处理层级 控制器不跟着 没办法刷蒙皮 # 错误: file: H:/Autodesk/May…