golang内存对齐

为什么要内存对齐?

CPU访问内存时,以CPU的位数为单位进行访问。
如果访问未对齐的内存,处理器需要做两次内存访问,对齐的内存的访问可能仅需要一次,利用内存对齐后提升读取速度。
golang结构体内存对齐规则
在代码编译阶段,编译器会对数据的存储布局进行对齐优化。
对于golang结构体来说,在编译后,就已经确定好了结构体的大小以及各成员相对首部的偏移量。
如下两个结构体T1和T2,成员变量相同,但是成员位置不同

type T1 struct {a int8b int64c int16
}type T2 struct {a int8c int16b int64
}func TestAlign(t *testing.T) {var u1 T1var u2 T2println(unsafe.Sizeof(u1)) // 24println(unsafe.Sizeof(u2)) // 16
}

打印内存地址

u1->a的地址 0xc0002d7e40 // 占用一个字节
u1->b的地址 0xc0002d7e48 // 占用两个字节,前面填充一个字节
u1->c的地址 0xc0002d7e50 // 占用八个字节,前面填充四个字节u2->a的地址 0xc0002d7e30 // 占用一个字节
u2->c的地址 0xc0002d7e32 // 占用两个字节,前面填充一个字节
u2->b的地址 0xc0002d7e38 // 占用八个字节,前面填充四个字节

在64位机器上执行,T2的结构体内存对齐为如下所示:
在这里插入图片描述

规则

结构成员需要对齐

第一个的成员相对于结构体首地址的offset = 0
非第一个成员相对于结构体首地址的 offset = min(该成员大小, 对齐值)*N倍
如有需要,编译器会在成员间加上填充字节

结构体间需要对齐

结构体的长度 = 成员中最大对齐值 * M倍

示例

bool大小占用1B,对齐值为1B
int32大小占用4B,对齐值为4B
int64大小占用8B,对齐值为8B
string大小占用16B,对齐值为8B
complex128大小占用16B,对齐值为8B// 结构体的总大小为:max(1, 8, 1) * 4 = 32
type T1 struct {a bool         // 0xc000042750,offset=0,占用1字节b complex128   // 0xc000042758,offset=min(16,8)*1 = 8,占用16字节c bool         // 0xc000042768,offset=min(1,1)*24 = 24,占用1字节
}// 结构体的总大小为:max(8, 1) * 3 = 24
type T2 struct {a complex128   // offset=0,占用16字节b bool         // offset=min(1,1)*16 = 16,占用1字节
}// 结构体的总大小为:max(1, 2) * 2 = 4
type T3 struct {a bool         // offset=0,占用1字节b int16        // offset=min(2,2)*1 = 2,占用2字节
}

特殊字段的内存对齐

空结构体被广泛作为各种场景下的占位符使用。一是节省资源(比如利用map实现set),二是空结构体本身就具备很强的语义。

type T1 struct {a struct{}b bool
}type T2 struct {a boolb struct{}
}func main() {var u1 T1println(unsafe.Sizeof(u1))   // 1println("u1->a的地址", &u1.a) // 0xc00004276dprintln("u1->b的地址", &u1.b) // 0xc00004276dvar u2 T2println(unsafe.Sizeof(u2))   // 2println("u2->a的地址", &u2.a) // 0xc00004276eprintln("u2->b的地址", &u2.b) // 0xc00004276f
}

空结构体字段放最后会额外占用1B内存,放在非最后位置不占用内存。
原因:
当空结构体字段定义到最后时,因为如果有指针指向该字段,返回的地址将在结构体之外,如果此指针一直存活不释放对应的内存,就会有内存泄露的问题(该内存不因结构体释放而释放)。

Hot path

hot path 是指执行非常频繁的指令序列。
访问结构体的第一个字段时,可以直接使用结构体的指针来访问第一个字段。
访问结构体的其他字段,除了结构体指针外,还需要计算偏移量。
在机器码中,偏移量是随指令传递的附加值,带上偏移量的指令序列会更长。同时CPU 还需要做一次偏移量与指针的加法运算,才能获取要访问的值的实际地址。
因此,访问第一个字段与访问其它字段相比,机器代码会更紧凑(长度短),执行速度也会更快(没有指针与偏移量的加法运算)。

示例

// sync.once中,官方解释可见英文,done使用很频繁,所以被放在结构体第一位

type Once struct {// done indicates whether the action has been performed.// It is first in the struct because it is used in the hot path.// The hot path is inlined at every call site.// Placing done first allows more compact instructions on some architectures (amd64/x86),// and fewer instructions (to calculate offset) on other architectures.done uint32m    Mutex
}

总结

  • 定义结构体时可以把类型相同的字段定义放一块,同时按照占用空间从小到大(或者从大到小)的顺序定义字段。
  • 结构体内嵌套空结构体时,不要放在最后一位。
  • 定义结构体时,可以考虑把常使用的字段放在第一位。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于身份的安全威胁正在迅速增长

根据端点安全和威胁情报供应商 CrowdStrike 发布的一份报告,目前最危险的网络安全威胁是能够访问给定系统合法身份信息的攻击者。 根据该报告,交互式入侵(该公司将其定义为攻击者积极工作以在受害者系统上实现某种非法目的的入侵)…

【Linux】深入理解进程概念

个人主页:🍝在肯德基吃麻辣烫 我的gitee:Linux仓库 个人专栏:Linux专栏 分享一句喜欢的话:热烈的火焰,冰封在最沉默的火山深处 文章目录 前言浅谈进程概念1. 进程和操作系统的联系2.描述进程的对象——PCB …

SQL ASNI where from group order 顺序 where和having,SQL底层执行原理

SQL语句执行顺序: from–>where–>group by -->having — >select --> order 第一步:from语句,选择要操作的表。 第二步:where语句,在from后的表中设置筛选条件,筛选出符合条件的记录。 …

51单片机学习-AT24C02数据存储秒表(定时器扫描按键数码管)

首先编写I2C模块,根据下面的原理图进行位声明: sbit I2C_SCL P2^1; sbit I2C_SDA P2^0;再根据下面的时序结构图编写函数: /*** brief I2C开始* param 无* retval 无*/ void I2C_Start(void) {I2C_SDA 1; I2C_SCL 1; I2C_SDA 0;I2C_S…

安防监控视频汇聚平台EasyCVR分发的FLV视频流在VLC中无法播放是什么原因?

众所周知,TSINGSEE青犀视频汇聚平台EasyCVR可支持多协议方式接入,包括主流标准协议国标GB28181、RTSP/Onvif、RTMP等,以及厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。在视频流的处理与分发上,视频监控…

安全防御(3)

1.总结当堂NAT与双机热备原理,形成思维导图 2.完成课堂nat与双机热备试验 引用IDS是指入侵检测系统,它可以在网络中检测和防御入侵行为。IDS的签名是指根据已知入侵行为的特征制定的规则,用于检测和警告可能存在的入侵行为。签名过滤器可以根…

人工智能编程软件 python,python人工智能编程入门

大家好,给大家分享一下人工智能python编程具体做什么,很多人还不知道这一点。下面详细解释一下。现在让我们来看看! 有不少同学学习 Python 的原因是对人工智能感兴趣,有志于从事相关行业。今天我们来聊聊这个方向所需要的一些技能…

8月8日上课内容 研究nginx组件rewrite

location 匹配uri location 匹配的规则和优先级。(重点,面试会问,必须理解和掌握) nginx常用的变量,这个要求掌握 rewrite:重定向功能。有需要掌握,有需要理解的。 location匹配:…

【单片机】51单片机串口的收发实验,串口程序

这段代码是使用C语言编写的用于8051单片机的串口通信程序。它实现了以下功能: 引入必要的头文件,包括reg52.h、intrins.h、string.h、stdio.h和stdlib.h。 定义了常量FSOC和BAUD,分别表示系统时钟频率和波特率。 定义了一个发送数据的函数…

BIO,NIO,AIO总结

文章目录 1. BIO (Blocking I/O)1.1 传统 BIO1.2 伪异步 IO1.3 代码示例 1.4 总结2. NIO (New I/O)2.1 NIO 简介2.2 NIO的特性/NIO与IO区别1)Non-blocking IO(非阻塞IO)2)Buffer(缓冲区)3)Channel (通道)4)Selector (选择器) 2.3 NIO 读数据和写数据方式…

1749. 任意子数组和的绝对值的最大值

诸神缄默不语-个人CSDN博文目录 力扣刷题笔记 文章目录 1. 暴力搜索2. 动态规划3. 前缀和 1. 暴力搜索 直接用2个指针从索引0开始找到最后一个索引,时间复杂度大概是 O ( n 2 ) O(n^2) O(n2)吧,总之这么搞不行,以下是我用Python写的一些典型…