C++ 中内存对齐原理及作用
struct/class/union内存对齐原则有四个:
1).数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon。
2).结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部”最宽基本类型成员“的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。
3).收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的”最宽基本类型成员”的整数倍.不足的要补齐.(基本类型不包括struct/class/uinon)。
4).sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。
实例解释:下面以class为代表
No.1
class Data
{char c;int a;
};cout << sizeof(Data) << endl;
No.2
class Data
{char c;double a;
};cout << sizeof(Data) << endl;
显然程序No.1 输出的结果为 8 No.2 输出的结果为 16 .
No.1最大的数据成员是4bytes,1+4=5,补齐为4的倍数,也就是8。而No.2为8bytes,1+8=9,补齐为8的倍数,也就是16。
No.3
class Data
{char c;int a;char d;
};cout << sizeof(Data) << endl;
No.4
class Data
{char c;char d;int a;
};cout << sizeof(Data) << endl;
No.3运行结果为 12 No.4运行结果为 8
class中的数据成员放入内存的时候,内存拿出一个内存块来,数据成员们排队一个一个往里放,遇到太大的,不是把自己劈成两半,能放多少放多少,而是等下一个内存块过来。这样的话,就可以理解为什么No.3,No.4两端的代码输出结果不一样了,因为左边是1+(3)+4+1+(3)=12,而右边是1+1+(2)+4=8。括号中为补齐的bytes。
No.5
class BigData
{char array[33];
};class Data
{BigData bd;int integer;double d;
};cout << sizeof(BigData) << " " << sizeof(Data) << endl;
No.6
class BigData
{char array[33];
};class Data
{BigData bd;double d;
};cout << sizeof(BigData) << " " << sizeof(Data) << endl;
No.5和No.6运行结果均为: 48
在默认条件下,内存对齐是以class中最大的那个基本类型为基准的,如果class中有自定义类型,则递归的取其中最大的基本类型来参与比较。在No.5和No.6中内存块一个接一个的过来接走数据成员,一直到第5块的时候,BigData里只剩1个char了,将它放入内存块中,内存块还剩7个bytes,接下来是个int(4bytes),能够放下,所以也进入第5个内存块,这时候内存块还剩3bytes,而接下来是个double(8bytes),放不下,所以要等下一个内存快到来。因此,No.5的Data的size=33+4+(3)+8=48,同理No.6应该是33+(7)+8=48。
顺便提一下Union: 共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。
No.7
class A
{int i;char c1;
}class B:public A
{char c2;
}class C:public B
{char c3;
}
sizeof(C)结果是多少呢,gcc和vs给出了不同的结果,分别是8、16
gcc中:C相当于把所有成员i、c1、c2、c3当作是在一个class内部,(先继承后对齐)
vs中:对于A,对齐后其大小是8;对于B,c2加上对齐后的A的大小是9,对齐后就是12;对于C,c3加上对齐后的B大小是13,再对齐就是16 (先对齐后继承)
关于c++对象继承后的内存布局,更详细的分析可以《深度探索参考c++对象模型》第三章
内存对齐的主要作用是:
1、 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。具体原因稍后解释。
这是普通程序员心目中的内存印象,由一个个的字节组成,而CPU并不是这么看待的。
CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度) 本人把它翻译为“内存读取粒度” 。
假设CPU要读取一个int型4字节大小的数据到寄存器中,分两种情况讨论:
1、数据从0字节开始
2、数据从1字节开始
再次假设内存读取粒度为4。
当该数据是从0字节开始时,很CPU只需读取内存一次即可把这4字节的数据完全读取到寄存器中。
当该数据是从1字节开始时,问题变的有些复杂,此时该int型数据不是位于内存读取边界上,这就是一类内存未对齐的数据。
此时CPU先访问一次内存,读取0—3字节的数据进寄存器,并再次读取4—5字节的数据进寄存器,接着把0字节和6,7,8字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。
这还属于乐观情况了,上文提到内存对齐的作用之一为平台的移植原因,因为以上操作只有有部分CPU肯干,其他一部分CPU遇到未对齐边界就直接罢工了。
C++ 中内存对齐原理及作用相关推荐
- 详解JSP 中Spring工作原理及其作用
详解JSP 中Spring工作原理及其作用 1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作. 2.Dispat ...
- linux 内存使用原理,linux中内存使用原理
首先介绍一下linux中内存是如何使用的. 当有应用需要读写磁盘数据时,由系统把相关数据从磁盘读取到内存,如果物理内存不够,则把内存中的部分数据导入到磁盘,从而把磁盘的部分空间当作虚拟内存 来使用,也 ...
- linux中umask的原理和作用,Linux 的umask详解
1.由权限得到umask的值 umask是一个系统变量,是一个由3个八进制数字组成的值,具体含义见表:每个数字都是八进制值1.2.4的OR操作结果. 作用:当文件被创建时,为文件的访问权限设定一个掩码 ...
- 7. 重磅硬核 | 一文聊透对象在JVM中的内存布局,以及内存对齐和压缩指针的原理及应用
重磅硬核 | 一文聊透对象在JVM中的内存布局,以及内存对齐和压缩指针的原理及应用 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章?<从内核角度看IO ...
- 一文聊透对象在JVM中的内存布局,以及内存对齐和压缩指针的原理及应用
大家好,我是bin,又到了每周我们见面的时刻了,我在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以一个C10k的问题为主线,从内核角度详细阐 ...
- 内存对齐的规则以及作用
内存对齐能够用一句话来概括: "数据项仅仅能存储在地址是数据项大小的整数倍的内存位置上" 比如int类型占用4个字节.地址仅仅能在0,4.8等位置上. 由一个程序引入话题: //环 ...
- c语言编程中如何对其,C语言内存对齐详解(3)
在minix的stdarg.h文件中,定义了如下一个宏: /* Amount of space required in an argument list for an arg of type TYPE ...
- 内存对齐的规则以及作用 verygood!的一篇文章!
原文转自:http://www.cppblog.com/snailcong/archive/2009/03/16/76705.html 首先由一个程序引入话题: //环境:vc6 + windows ...
- C语言:--位域和内存对齐
位域 位域是指信息在保存时,并不需要占用一个完整的字节,而只需要占几个或一个二进制位.为了节省空间,C语言提供了一种数据结构,叫"位域"或"位段". " ...
最新文章
- SAP模块常用增强总结
- 《科学》:中国科学家揭示,人脑中间神经元多样性从何而来?
- 《GTA 5》走进现实!AI逼真还原游戏街景,还能“脑补”细节 | 英特尔出品
- 这是我见过最蛋疼的注册中心与API网关实践!
- 网站优化的“内忧外患”需兼顾
- Qt添加对Android的OpenSSL支持
- 2013电赛总结【西电专用】
- 怎么将tflite部署在安卓上_tensorflow从训练自定义CNN网络模型到Android端部署tflite...
- PCI-E 5.0标准公布:速度再次翻番达32GT/s
- 用ExpandableListView实现好友分组
- 导入php插件_漏洞分析丨WordPress评论插件wpDiscuz任意文件上传
- MongoDB几个完整的库表设计实例
- idea git提交代码步骤(转载)
- WinRAR5.40版 无广告
- OPENCV运动追踪研究和PYTHON及JAVA实现
- 【参会指南】PPP全球数字资产投资峰会之金融科技区块链支持可持续发展
- pip安装出现Script file ‘D:\ProgramData\Anaconda3\Scripts\pip-script.py‘ is not present.
- Linux系统安全加固设置详细教程
- Android App 导出APK安装包以及制作App图标讲解及实战(图文解释 简单易懂)
- Debian Bullseye 更新源备份
热门文章
- Android nba2k14 mod,NBA 2K14 真实化合集游戏MOD
- openssh离线升级8.8
- Halo 博客系统部署日记--Docker
- c#加粗代码_C# 按钮改变字体样式和加粗和斜体
- Ubuntu 16.04 开启BBR加速
- 正则表达式匹配数字(可为整数或带小数包括0)
- 10大开源的Web应用防火墙介绍
- 城市智慧交通规划方案
- 笔记本计算机点管理点不开,电脑黑屏只有鼠标箭头任务管理器打不开 怎么解决...
- 自适应方案:在vue项目中使用postcss-px2rem