c++ 内存对齐那些事

一.内存对齐介绍

目前的计算机系统中 cpu都是按照字节进行读取存储的内存数据,访问某一个变量的时候 需要在特定的地址空间中访问,此时就需要各种不同类型的变量在内存空间中按照一定的规则进行排放,而不是一个接一个的进行有序排放。所以现代编译器中都会对内存进行自动的对齐。

struct struct1
{
    char a;
    int b ;
    short c;
};

上面的struct1 所占的空间大小是12,char a 是 1 个字节,int b 是4 个字节,short  c 是2 个字节,经过内存对齐后大小是12(后面会说明为啥是12)

 

二.内存对齐的作用

1.平台原因

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。某些架构的cpu读取没有对齐的内存数据时,可能会出错。

2.性能原因  (可以提高存取效率)

对于一个32位的操作系统,假设每次读取都是从偶地址位置开始读取。一个int 型变量,如果存取在偶地址的开始位置,那么系统可以在一个读周期中取出这个int 变量,如果要是存放在奇地址位置,那么系统需要读取两次,对两次读取后的结果进行拼接才能得到这个int 型变量值。性能明显增加。

三.内存是怎么对齐的?

每个平台都是有自己的编译器系数,通过预编译命令#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中 n 就是你要指定的“对齐系数”。

对齐的规则:

(1).对齐的有效值是,取 #pragma pack(n) 中n 和结构体中最长数据长度的较小的一个。

(2).结构体struct中的成员变量在内存中的分配是连续的,struct内的首地址也就是第一个数据成员的地址,亦可理解为 struct内第一个数据成员的地址与struct首地址的偏移量offset = 0.

(3).struct内数据成员,在第一个数据成员之后,每一个数据成员距离struct首地址的offset的距离是有效对齐值的整数倍,如果不是整数倍,那么在对齐的时候,会在这个成员的数据前添加空的字节达到整数倍。(有效对齐值指的是#pragma pack(n) 中n 和结构体中数据成员最长长度进行比较,取其中的较小的一个)

(4). 结构体的整体对齐准则

数据成员对齐之后,还要进行整体对齐。 如果数据对齐完成时struct的大小不是对齐有效值的整数倍。就要在struct的最后添加空字节直到对齐。看下面一个简单的例子,n = 8, struct中 int b的长度最长 是占4个字节,所以对齐有效值为4

struct struct1
{
    char a;
    int b ;
    short c;
};

char a 的offset是0,a占一个字节,所以需要在a 钱添加3个空字节,000x,此时b 的offset是4,是对齐有效值的整数倍,不需要添加空字节,xxxx,short c的offset是8,且c长度是2,所以一共是4+4+2 = 10,不是有效值的倍数,所以后面添加2个空字节进行对齐,此时struct1的长度是12。

四。简单实例

从上面 我们可以看出来,内存对齐的优点,在某种程度上 可以提高程序的性能。下面我们看一个简单的例子来说明这个问题。

#include <iostream>
#include <sys/time.h>
#include <iostream>
#include<time.h>
#include<stdlib.h>
#include <stdio.h>

using namespace std;

struct struct1   //没有对齐
{
    char a;
    int b ;
    short c;
};

struct struct2  //已经对齐
{
    short c;
    char a;
    int b;
};
 
 void test1()
 {
	 struct timeval start, end;
	 gettimeofday(&start,NULL);
	 for(int i=0;i< 10000000; i++)
	 {
		 struct1  s1;
		 s1.b = 1;
	 }
	 gettimeofday(&end,NULL);
	 long long int time = ( end.tv_sec - start.tv_sec ) * 1000 * 1000 +  end.tv_usec - start.tv_usec;
	 cout << "** test1 cost time is :" << time << endl;
 }
 
 void test2()
 {
	 struct timeval start, end;
	 gettimeofday(&start,NULL);
	 for(int i=0;i< 10000000; i++)
	 {
		 struct2  s2;
		 s2.b = 1;
	 }
	 gettimeofday(&end,NULL);
	 long long int time = ( end.tv_sec - start.tv_sec ) * 1000 * 1000 +  end.tv_usec - start.tv_usec;
	 cout << "** test2 cost time is :" << time << endl;
 }
 
 int main()
 {
	 struct1 s1;
	 cout << " s1 size is " << sizeof(s1) << endl;
	 
	 struct2 s2;
	 cout << " s2 size is :" << sizeof(s2) << endl;
	 test1();
	 test2();
	
	 return 0;
 }
 
 

运行的结果如下:

struct1没有进行内存对齐,struct2进行内存对齐,从运行结果可以看出没有进行内存对齐的数据结构 计算时候 性能消耗比内存对齐的要大。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值