内存对齐

内存对齐完全指南 对齐的根本目的:优化内存访问效率硬件要求:不同架构对对齐的要求不同,但都与内存访问机制相关填充规则:填充是为了让每个成员和整个结构体满足对齐要求性能影响:正确的对齐能显著提高内存访问性能,特别是在多线程环境中。 阅读详情

内存对齐

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。
对于内存对齐问题,主要存在于struct和union等复合结构在内存中的分布情况,许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们要求这些数据的首地址的值是某个数M(通常是4或8);对于内存对齐,主要是为了提高程序的性能,数据结构,特别是栈,应尽可能在自然边界上对齐,经过对齐后,cpu的内存访问速度大大提升。

Windows中默认对齐数为8,Linux中默认对齐数为4;

内存对齐的主要作用(原因)

1、平台原因(移植原因)

  • 不是所有的硬件平台都能访问任意地址上的任意数据的;
  • 某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因

  • 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
  • 为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

内存对齐规则

编译器中提供了#pragma pack(n)来设定变量以n字节对齐方式

在内存中,编译器按照成员列表顺序分别为每个结构体变量成员分配内存,当存储过程中需要满足边界对齐的要求时,编译器会在成员之间留下额外的内存空间。如果想确认结构体占多少存储空间,则使用关键字sizeof,如果想得知结构体的某个特定成员在结构体的位置,则使用offsetof宏(定义于stddef.h)。

  1. 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。即排列在后面的成员其当前偏移量必须是当前成员类型的整数倍。
  2. 结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
  3. 结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

总结:
内存对齐的原则:

  1. 结构体变量的首地址能够被其最宽基本类型成员大小与对齐基数中的较小者所整除;
  2. 结构体每个成员相对于结构体首地址的偏移量 (offset) 都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节 (internal padding);
  3. 结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节 (trailing padding)。

假如我们的一个结构体有1个int,两个char, 那么不同的排列顺序,会造成结构体的大小不一致。
在这里插入图片描述

#include<iostream>
using namespace std;
struct A{
    char a;
    int b;
    short c;
};

struct B{
    short c;
    char a;
    int b;
};
int main(){
    cout<<sizeof(A)<<endl;
    cout<<sizeof(B)<<endl;
    return 0;
}

以上面结构体A为例,第一个成员a是char类型,占用1个字节空间,偏移量为0,第二个成员b是int类型,占用4个字节空间,按照规则1,b的偏移量必须是int类型的整数倍,所以编译器会在a变量后面插入3字节缓冲区,保证此时b的偏移量(4字节)是b类型的整数倍(当前恰好是1倍),第3个成员c为short类型,此时c的偏移量正好是4+4=8个字节,已经是short类型的整数倍,故b与c之间不用填充缓冲字节。但这时,结构体A的大小为8+2=10个字节,按照规则2,结构体A大小必须是其最大成员类型int的整数倍,所以在10个字节的基础上再填充2个字节,保证最后结构体大小为12,以符合规则2.

数据成员--前面偏移量-- 成员自身占用
(char) a01
缓冲补齐13(规则1)
(int) b44
(short) c82
缓冲补齐102(规则2)

类似的,结构体B成员的分析如下:

数据成员--前面偏移量--成员自身占用
short c02
char a21
缓冲补齐31(规则1)
int b44

另一个更复杂的例子:

struct BU
{
    int number;             //4字节
    union UBffer
    {
        char buffer[13];    //填充3字节,该成员占16字节空间
        int number;
    }ubuf;
    int aa;                 //占4字节空间,当前偏移量已补齐为20
    double dou;             //占8字节空间
}bu;//sizeof(BU) = 4 + 13 + 3(补齐) + 4 + 8 = 32

结构体BU稍微变换下aa和dou成员顺序,则结果就大不相同:

struct BC
{
    int number;             //4字节
    union UBffer
    {
        char buffer[13];    //填充7字节,该成员占20字节空间
        int number;
    }ubuf;
    double dou;             //占8字节空间,当前偏移量已补齐为24
    int aa;                 //占4字节空间,当前占用空间36字节,最大double类型,还需要根据规则2补齐
}bu;//sizeof(BC) = 4 + 13 + 7(规则1补齐) + 8 + 4 + 4(规则2补齐) = 40 (8的整数倍)

我们可能对于结构体类包含union类型成员抱有疑虑,再考虑下面实例:

struct BD
{
    short number;
    union UBffer
    {
        char buffer[13];
        int number;
    }ubuf;
}bc;

运行结果是sizeof(BD) = 2 + 2 + 13 +3 = 20,可能你会问,为什么不是2+13+1 = 16,这是因为union类型比较特殊,计算union成员的偏移量时,需要根据union内部最大成员类型来进行缓冲补齐,所以为了保证偏移量为union最大成员int类型的整数倍,需要在number(short类型)后面填充2个字节,前面例子中number是int类型,就没有这个必要了。

再比如:

struct BE
{
    short number;
    union UBffer
    {
        char buffer[13];
        double number;
    }ubuf;
}bc;

它的运行结果是sizeof(BE) = 2 + 6 + 13 + 3 = 24,number后面为了与double类型进行对齐而补齐了6个字节,最后再按照规则2补齐了3个字节。

考虑规则3:

举个例子,在#pragma pack(1)时,以1个字节对齐时,属于最简单的情况,结构体大小是所有成员的类型大小的和。所以sizeof(BU) = sizeof(BC) = 29,这时与成员变量顺序不再相关。其他指定的字节对齐也很好分析。一般而言,奇数个字节对齐没有意义,正常情况下,编码人员不关心编译器对内存对齐所作的工作。

内存对齐的优点

  1. 便于在不同的平台之间进行移植,因为有些硬件平台不能够支持任意地址的数据访问,只能在某些地址处取某些特定的数据,否则会抛出异常;
  2. 提高内存的访问效率,因为 CPU 在读取内存时,是一块一块的读取。
C/C++内存对齐规则(结构体、联合体、类) 本篇博客介绍了内存对齐的规则,包括结构体嵌套结构体、结构体嵌套数组的例题;介绍了如何求union联合体的内存大小;还介绍了如何计算C++的类的内存大小 阅读详情

相关推荐

手推反向传播+numpy实现

反向传播的重要性不必多说,手推也是必备基础,大厂面试要求用numpy实现一下BP也是经常的事。下面以一个简单的两层网络为例(简单到连bias都没有的那种),真·手推反向传播+numpy实现。 说明: input:输入 net_h:隐层 S(x):sigmoid简写 SD(x):sigmoid导数的简写 out_h:隐层经过sigmoid激活的输出 net_o:输出层 out_o:经过经过sigmoid激活的输出层,也就是最后的输出 target(简写t1、t2):Ground...

xian0710830114的专栏 1238

详解内存对齐

欢迎大家点击上方文字「Golang梦工厂」关注公众号,设为星标,第一时间接收推送文章。前言哈喽,大家好,我是asong。好久不见,上周停更了一周,因为工作有点忙,好在这周末闲了下来,就赶紧...

qq_39397165的博客 2万+

告别抓瞎!手把手教你用Keysight Infinium和M8040完成PCIe 5.0 TX/RX信号完整性测试

本文详细介绍了如何使用Keysight Infinium示波器和M8040误码仪完成PCIe 5.0 TX/RX信号完整性测试。从测试前的设备准备、软件配置到具体的TX信号测试步骤和RX容限测试实战,提供了全面的操作指南和常见问题解决方案,帮助工程师高效完成PCIe 5.0合规性测试。

weixin_30911451的博客 503

关于内存对齐你需要了解的事

这篇文章的目的是带你了解什么是内存对齐,具体的内存对齐的细节、处理方式、不同架构则不会去详细讲解,只做科普文用。内存对齐和数据在内存中的位置有关。内存对齐以字节为单位进行,一个变量的内存地址如果正好等于它的长度的整数倍,则称为自然对齐。比如在32位 cpu 下,一个 u32 的内存地址为0x00000004 ,则属于自然对齐。内存空间按照字节进行划分,理论上可以从任意地址开始读取,实际上会要求读取数据的首地址是某一个值的整数倍。

日常学习记录 3406

基于Multisim的模电调幅发射机仿真设计

振荡器产生的高频信号的功率很小,所以有必要对高频信号进行功率放大,有利于信号的调制发射。缓冲电路将主振荡器和高频功放电路相隔离,以减小功放电路对主振荡器的影响。缓冲电路可以用射极跟随器电路来实现,其作用就是前后级的阻抗相互匹配,减小前后级的影响。总电路的仿真结果见下图:示波器1~4分别是主振荡器、缓冲电路、高频放大电路和调幅电路的输出波形。由于载波频率稳定度≤10-3,所以可以采用并联型改进电容反馈式三端振荡器(Seiler电路)谐振回路,滤除其他频率的成分,得到与载波(假设。(1)缓冲电路的设计与实现。

Eve223322的博客 4567

数据科学常见模型总结(二)-倾向性得分匹配模型

PSM的核心思想是从未受干预的用户群体中,找到和干预对象一模一样的用户,这样就可以把因果效应归因到干预上。

wudelong0112的专栏 4887

【C/C++】内存对齐(超详细,看这一篇就够了)

下面的结论均为系统默认对齐规则下进行的: 通常情况:我总结的规律如下:结构体中间:各结构体的起始地址按照各个类型变量默认规则进行摆放,但除了 char 类型变量(详见一),char 类型变量一般遵循 2 的倍数地址开始存储。详见例2。结构体最后(重要):视结构体中最大类型是哪一个,如果是像 int 类型那样是 4 个字节的,并且结构体的结尾地址不满足 4 的倍数的话,向离最近的 4 的倍数地址补齐;如果是像 double 类型那样是 8 个字节的,并且结构体的结尾地址不满足 8 的倍数的话,向离最近的 8

涛涛子的博客 3万+

LVGL 组件对齐方式说明

本文说明 LVGL(以 v8 为例)中常用的 lv_align_t对齐选项的含义与用法,对应界面设计工具里下拉列表中的以及等命名。

摸鱼专家 130

内存对齐、内存对齐规则解释、内存对齐原理

一、内存对齐的原因 我们都知道计算机是以字节(Byte)为单位划分的,理论上来说CPU是可以访问任一编号的字节数据的,我们又知道CPU的寻址其实是通过地址总线来访问内存的,CPU又分为32位和64位,在32位的CPU一次可以处理4个字节(Byte)的数据,那么CPU实际寻址的步长就是4个字节,也就是只对编号是4的倍数的内存地址进行寻址。同理64位的CPU的寻址步长是8字节,只对编号是8的倍数的内存...

草帽~小子^的博客 7393

111. 如何创建 SAP ABAP 锁对象(Lock Object)和加锁以及解锁函数

至此,我们完成了 ABAP 系统锁机制和加锁解锁函数的介绍。有了这些基础知识,大家就能在实际工作中,使用 Lock Object 和加锁解锁函数,编写出支持并发访问控制的 ABAP 应用程序了。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1532

【PowerBI专栏】PowerBI导入MYSQL数据库

本文介绍了在PowerBI中连接MySQL数据库的方法。首先需要下载并安装MySQL官方.NET连接驱动(推荐8.4.0版本),安装完成后重启PowerBI。连接时需填写服务器IP和数据库名称等必填参数。文章详细说明了连接配置步骤,包括账户设置、数据表选择以及可能遇到的数据格式转换问题处理。最后指导用户完成数据清洗后进入PowerPivot进行后续计算。特别提醒最新9.4版本可能存在兼容性问题,建议使用稳定的8.4版本连接器。

技术与管理的平衡木- 689

C++ 内存对齐

二、内存对齐规则 首先了解两个概念: 1.每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。32位系统,gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数。 2.有效对齐值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。 然后明确内存对齐的两个规则: 1.结构体第一个成员的偏移量(offset)为0,以后每个成员相对于结构体首地址的 off

weixin_43816121的博客 4904

【系统架构设计师】二十六、论文写作要点

论文写作概述:时间所需120分钟;题目可四选一,必有一题考察软件架构,总有一款适合你;考察形式是机试(开心,再也不用担心字丑了),约2500字。

帅次的博客 4597

什么是内存对齐以及作用

什么是内存对齐? 为了解释这个问题,先来介绍下面的例子: #include<iostream> using namespace std; struct A { char a; short b; int c; }; struct B { short b; int c; char a; }; int main() { cout<<sizeof(A)&...

qq_41909314的博客 6096

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

什么是内存对齐

内存对齐

qq_42376419的博客 1535

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

内存对齐以及如何关闭内存对齐

内存对齐以前接触过,知道有这么回事,昨天面试,面试官问了一个结构体内存分配相关的问题: struct _A{ int a; int b; char c; }A; sizeof(A)=?(32位机器) 我一想这要涉及到内存对齐啊,sizeof(A)=12 啊, 没想到接下来面试官的一个问题就是:那如果我想节省内存,不让他内存对齐,就分配9个字节,怎么办? 当时就蒙了,一直没想过这个

a1205137569的博客 4358

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

什么是内存对齐?内存对齐的原则?为什么要进行内存对齐,有什么优点?

是指在计算机中,为了提高内存访问效率,数据在内存中的存储地址需要满足特定的对齐要求。不同的数据类型(如intfloatdouble等)在内存中的存储地址往往有特定的对齐边界,通常是该数据类型大小的倍数(比如int通常对齐到 4 字节,double通常对齐到 8 字节)。

weixin_47151388的博客 2345

小心内存对齐

什么是内存对齐?CPU在读取内存地址的时候,一定按照一定的偏移量去读取,不知道你发现了没有,我们没有看到一个变量的大小是 3 个字节的,都是 1 个字节,2个字节,4个字...

嵌入式Linux 1178

linux内存对齐

一,内存地址对齐的概念    计算机内存中排列、访问数据的一种方式,包含基本数据对齐和结构体数据对齐。    32位系统中,数据总线宽度为32,每次能够读取4字节数据。地址总线为32,最大寻址空间为4GB。但是由于最低位A[0]~A[1]是不用于寻址的,因此只能访问4的倍数的地址空间,但是寻址空间还是2^30*字长=4GB。   因此内存中除了结构体中成员变量之外的基本类型的开始

逐波与逆流 2784

关于内存对齐

C/C++内存对齐

BuXianShan的博客 208

内存对齐,只要是跨平台的都要内存对齐

内存对齐 内存对齐,只要是跨平台的都要内存对齐,c\c++\java\python 其中c\c++是手动释放内存堆空间 动态开辟或new出来的。 jvm是java自动释放内存堆管理。但是有些错误的写法会照成内存泄漏,或内存溢出。 python 内存是由私有堆空间管理的,所有python对象和数据结构,都存在私有堆空间,程序员没有访问私有堆的权限,只有解释器才能操作。 python 万物皆为对象,对内存封装的很好,所以python的基本数据类型所用的内存,远大于存放纯数据类型所占用的内存, c++内存管理

qq_44985337的博客 549

内存对齐详解

假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的联系四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器.这需要做很多工作。**考虑4字节存取粒度的处理器取int类型变量(32位系统),该处理器只能从地址为4的倍数的内存开始读取数据。现在有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。

zhexiao 1248
上一篇: IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
下一篇: C++的特性
GoodLinGL
博客等级 码龄6年 120粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值