C语言的内存对齐
从一个例子开始
象下面这样定义的结构体占几个字节?
typedef struct{
char a;
int i;
} Sample;
char占1个字节,int占4个字节,答案是5个字节? 错了。如果用 gcc 编译,sizeof(Sample) 的结果是8个字节。
这是怎么回事?进一步观察,Sample第0个字节是a, 而Sample的成员int i从第4个字节开始。 这是编译器为了内存对齐所做的优化。
什么是内存对齐
比如数据总线有32位,它访存只能4个字节4个字节地进行。 0-3,4-7,8-11,12-15,…… 即使我们需要的数据只占一个字节,也是一次读取4个字节。 一个字节的数据不管地址是什么,都能通过一次访存读取出来。 而如果要读取的数据是一个字节以上,比如两个字节, 如果该数据的内存地址是0x03,则需要两次才能读取该数据, 第一次读0x00-0x03,第二次读0x04-0x07。 这个数据就跨越了访存边界。
而相对CPU的运算来说,访存是非常慢的,所以要尽量减少访存次数。 为了减少跨越访存边界的数据引起的访存开销, 所以编译器会进行内存对齐,即把变量的地址做一些偏移, 目的是一次访存就读出数据,不然的话也要以尽可能少地访存次数读出数据。
如上一个例子中那样,整型成员i的地址做4个字节的偏移, 而Sample对象的地址也会做4字节边界的对齐, 这样i的地址始终是4的倍数,从而使得i不跨越访存边界, 能一次读出它的值。
尽可能少的内存占用
typedef struct{
char a;
char b;
int i;
} Sample1;
Sample1占多少空间呢?仍然是8个字节。 a在第0个字节,b在第1个字节,i占4-7字节。 这是内存对齐的原则,占用尽量少的内存。 如果在b之后,还有char类型的成员c和d,同样是占8个字节。 a,b,c,d在0-3字节。
数据成员顺序影响内存的占用
typedef struct{
char a;
int i;
char b;
} Sample2;
Sample2的数据成员和Sample1的数据成员相同,只是顺序不一样, 是否占用一样多的内存呢?答案是不一样。 Sample1占用8字节,而Sample2占用12个字节!
这是为什么呢?32位机器上,访存单元是4字节。 对于多于4字节的数据,以4字节为单位做内存对齐的。 所以对于上述的结构体数据的地址分配,都是4的倍数。 对于结构体内部,以数据成员的最大长度为对齐单位。 如果数据成员的长度超过4字节,仍然以4字节为对齐单位,这是因为访存单元就是4字节。 在Sample2的定义中,因为int是4字节,所以以4字节为内存对齐的单位。
在Sample2中,对于a来说,只占一个字节,无所谓对不对齐,它在0字节。 i是int类型,要对齐,在4-7字节。 b在8字节,虽然它只占一个字节,但因为结构体内是以4字节为单位对齐的, 所以编译器一下多分配出4个字节,所以共占了12个字节。
以上的Sample1和Sample2的例子说明,即使是同样的结构体,如果数据成员的顺序不同,所占的内存空间可能是不同的。
总结
如果我们对内存对齐有概念,在定义结构体的时候就会留心数据成员的顺序,从而能 减少程序的内存占用。
以前我使用变量存放较小的整数时,为了减小内存占用,往往把变量定义成char型, 但现在明白了,因为编译器的内存对齐,节省内存的效果并没有那么理想。
如果内存真的很受限,可以用 #pragma pack(1) 告诉编译器关闭内存对齐。
C语言的内存对齐的更多相关文章
- C语言中内存对齐规则讨论(struct)
C语言中内存对齐规则讨论(struct) 对齐: 现代计算机中内存空间都是按着byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地 ...
- C语言中内存对齐方式
一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...
- c语言中内存对齐问题
在最近的项目中,我们涉及到了“内存对齐”技术.对于大部分程序员来说,“内存对齐”对他们来说都应该是“透明的”.“内存对齐”应该是编译器的“管辖范围”.编译器为程序中的每个“数据单元”安排在适当的位置上 ...
- C语言中内存对齐与结构体
结构体 结构体是一种新的数据类型,对C语言的数据类型进行了极大的扩充. struct STU{ int age; char name[15]; }; struct STU a; //结构体实例 str ...
- C语言中内存对齐
今天一考研同学问我一个问题,一个结构体有一个int类型成员和一个char类型成员,问我这个结构体类型占多少个字节,我直接编个程序给他看结果.这个结构体占八个字节,咦,当时我蛮纳闷的,一个int类型四个 ...
- Go中由WaitGroup引发对内存对齐思考
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码时14.4 WaitGroup使用大家都会,但是其中是怎么实现的我们 ...
- 解析C语言结构体对齐(内存对齐问题)
C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...
- C语言再学习之内存对齐
昨天看Q3的代码,看到有个_INTSAIZEOF的宏,着实晕了一阵.一番google后,终于明白,这个宏的作用是求出变量占用内存空间的大小,先看看_INTSAIZEOF的定义吧: #define _I ...
- C语言:内存字节对齐详解[转载]
一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...
随机推荐
- 从微信SDK看ProtoBuffer文件的生成
前言 Protocol Buffers (下面简称PB)是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它可用于通讯协议.数据存储等领域的语言无 ...
- <构建之法>第一二三章感悟
第一章: 看了大概了解软件从一个想法到最终成品的一个过程.软件先是由一个想法引出的,有那个想法,你需要一个工具去做什么,根据自己想要的功能大概做一个能实现基本功能的软件,对客户提出的要求进行完善,实现 ...
- svmtrain和svmpredict简介
转自:http://blog.sina.com.cn/s/blog_4d7c97a00101bwz1.html 本文主要介绍了SVM工具箱中svmtrain和svmpredict两个主要函数: (1) ...
- 【百度】大型网站的HTTPS实践(二)——HTTPS加密算法介绍
大型网站的HTTPS实践(二)——HTTPS加密算法介绍 原创 网络通信/物联网 作者:AIOps智能运维 时间:2018-11-09 15:09:43 358 0 前言 在上一篇文章中,我们简要 ...
- 微信小程序 功能函数 获取验证码*
yanZhengInput: function (e) { var that = this; var yanzheng = e.detail.value; var huozheng = this.da ...
- Rotate Array II
Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the array ...
- elasticsearch6 学习之并发控制
环境:elasticsearch6.1.2 kibana6.1.2 并发问题无处不在 一.基于_version 的并发控制 在提交数据前先检查提交数据的version与es中存储的ve ...
- SpringBoot(九)_springboot集成 MyBatis
MyBatis 是一款标准的 ORM 框架,被广泛的应用于各企业开发中.具体细节这里就不在叙述,大家自行查找资料进行学习下. 加载依赖 <dependency> <groupId&g ...
- 【Java并发编程】之五:volatile变量修饰符—意料之外的问题
volatile用处说明 在JDK1.2之前,Java的内存模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的.而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的 ...
- js判断浏览器语言实现网站国际化
一般国际化的网站至少是有中.英文两种语言的,然后就是在不同的语言环境下使用不同的语言页面. 1.实现原理 一般实现这种功能的方法,无非就是两种, 第一种,判断浏览器语言类型: 第二种,判断ip所属国家 ...