golang 内存对齐和填充规则

news/2025/3/3 3:28:33/

内存对齐和填充规则

  1. 对齐要求:每个数据类型的起始地址必须是其大小的倍数。

    • int8(1字节):不需要对齐。
    • int16(2字节):起始地址必须是2的倍数。
    • int32(4字节):起始地址必须是4的倍数。
    • int64(8字节):起始地址必须是8的倍数。
  2. 填充规则:如果当前偏移量不是下一个成员变量对齐要求的倍数,则编译器会在前一个成员后插入“填充字节”,以使下一个成员的起始地址满足对齐要求。

  3. 结构体总大小:结构体的总大小必须是其最大成员对齐大小的倍数,必要时会在结构体末尾添加额外的填充字节。

示例解析

示例 1:未优化的结构体
type Unoptimized struct {a int8   // 1 byteb int32  // 4 bytes, 需要4字节对齐c int16  // 2 bytes, 需要2字节对齐
}
  • a 占用 1 字节,起始地址为 0。
  • b 需要 4 字节对齐,但 a 只占用了 1 字节,因此在 a 后面需要填充 3 字节,使得 b 的起始地址为 4。
  • c 需要 2 字节对齐,b 占用 4 字节,所以 c 的起始地址为 8,不需要额外填充。
  • 结构体总大小为 10 字节(1 + 3 + 4 + 2),但为了使结构体大小为 4 字节对齐(最大成员 b 是 4 字节对齐),需要在末尾再填充 2 字节。

最终结构体大小为 12 字节。

示例 2:优化后的结构体
type Optimized struct {b int32  // 4 bytes, 需要4字节对齐c int16  // 2 bytes, 需要2字节对齐a int8   // 1 byte, 不需要对齐
}
  • b 占用 4 字节,起始地址为 0,符合 4 字节对齐。
  • c 需要 2 字节对齐,b 占用 4 字节,所以 c 的起始地址为 4,不需要额外填充。
  • a 占用 1 字节,c 占用 2 字节,所以 a 的起始地址为 6,不需要额外填充。
  • 结构体总大小为 7 字节(4 + 2 + 1),但为了使结构体大小为 4 字节对齐(最大成员 b 是 4 字节对齐),需要在末尾再填充 1 字节。

最终结构体大小为 8 字节。

图解填充规则

假设我们有一个结构体:

type Example struct {a int8   // 1 byteb int16  // 2 bytesc int32  // 4 bytes
}

我们可以用图来表示内存布局:

Offset: 0  1  2  3  4  5  6  7  8  9 10 11+--+--+--+--+--+--+--+--+--+--+--+--+| a| P| P| P| b| b| P| P| c| c| c| c|+--+--+--+--+--+--+--+--+--+--+--+--+
  • a 占用 1 字节,后面填充 3 字节(P 表示填充字节)。
  • b 占用 2 字节,后面填充 2 字节。
  • c 占用 4 字节。

调整顺序后:

type Example struct {c int32  // 4 bytesb int16  // 2 bytesa int8   // 1 byte
}

内存布局变为:

Offset: 0  1  2  3  4  5  6  7+--+--+--+--+--+--+--+--+| c| c| c| c| b| b| a| P|+--+--+--+--+--+--+--+--+
  • c 占用 4 字节。
  • b 占用 2 字节。
  • a 占用 1 字节,后面填充 1 字节。

最终结构体大小为 8 字节,比原来的 12 字节更紧凑。

总结

通过将占用较大内存空间的成员放在前面,可以减少编译器为了对齐而插入的填充字节数量,从而使结构体更加紧凑,节省内存。你可以使用 unsafe.Sizeof()unsafe.Alignof() 来验证这些结构体的实际大小和对齐方式。


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

相关文章

【计算机网络】OSI模型、TCP/IP模型、路由器、集线器、交换机

一、计算机网络分层结构 计算机网络分层结构 指将计算机网络的功能划分为多个层次,每个层次都有其特定的功能和协议,并且层次之间通过接口进行通信。 分层设计的优势: 模块化:各层独立发展(如IPv4→IPv6&#xff0c…

Linux10-共享队列

1.4共享队列 1.4.1共享内存 内存映射:避免数据的反复读写拷贝,提高了效率。 内存管理单元MMU:将物理内存与虚拟内存之间架起映射关系 1.创建共享内存 int shmget(key_t key,size_t size,int shmflg); 2.建立共享内存…

mysqldump 参数详解

mysqldump 是一个用于备份 MySQL 数据库的工具。它可以生成一组 SQL 语句,这些语句可以用来重现原始数据库对象定义和表数据。以下是一些常用的 mysqldump 参数及其详细解释: 常用参数 基本参数 --host=host_name, -h host_name: 指定 MySQL 数据库主机地址,默认为 localh…

【湖北省计算机信息系统集成协会主办,多高校支持 | ACM出版,EI检索,往届已见刊检索】第二届边缘计算与并行、分布式计算国际学术会议(ECPDC 2025)

第二届边缘计算与并行、分布式计算国际学术会议(ECPDC 2025)将于2025年4月11日至13日在中国武汉盛大召开。本次会议旨在为边缘计算、并行计算及分布式计算领域的研究人员、学者和行业专家提供一个高水平的学术交流平台。 随着物联网、云计算和大数据技术…

Kibana:Spotify Wrapped 第二部分:深入挖掘数据

作者:来自 Elastic Philipp Kahr 我们将比以往更深入地探究你的 Spotify 数据并探索你甚至不知道存在的联系。 在由 Iulia Feroli 撰写的本系列的第一部分中,我们讨论了如何获取 Spotify Wrapped 数据并在 Kibana 中对其进行可视化。在第 2 部分中&#…

AI人工智能机器学习之神经网络

1、概要 本篇学习AI人工智能机器学习之神经网络,以MLPClassifier和MLPRegressor为例,从代码层面讲述最常用的神经网络模型MLP。 2、神经网络 - 简介 在 Scikit-learn 中,神经网络是通过 sklearn.neural_network 模块提供的。最常用的神经网…

【pytest框架源码分析三】pluggy源码分析之hook注册调用流程

pluggy的hook调用,最重要的就是使用了__call__魔法函数,这个函数能够在我们调用实例时,自动调用这个函数,无需自己手动调用。 前面介绍了各个类的方法,这里简述下pluggy的调用流程(主要介绍主流程&#xff…

从【人工智能】到【计算机视觉】,【深度学习】引领的未来科技创新与变革

前几天偶然发现了一个超棒的人工智能学习网站,内容通俗易懂,讲解风趣幽默,简直让人欲罢不能。忍不住分享给大家,点击这里立刻跳转,开启你的AI学习之旅吧! 前言 – 人工智能教程https://www.captainbed.cn/l…