sizeof与内存对齐总结

1.基本类型

sizeof运算符返回类型或者数据对象的长度(字节),

  int a=1;
   float b=1.0;
   double c=1.0;
   long d=1;
   char e = '1'; 

    cout<<sizeof(a)<<" "<<sizeof(b)<<" "<<sizeof(c)<<" "<<sizeof(d)<<" "<<sizeof(e)<<endl;
    cout<<sizeof(int)<<" "<<sizeof(float)<<" "<<sizeof(double)<<" "<<sizeof(long)<<" "<<sizeof(char)<<endl;

输出:

4 4 8 8 1
4 4 8 8 1

2.静态数组

将sizeof运算符用于静态数组名,得到的是整个数组的字节数,用于数组元素,则得到的是元素长度。

int arr[3]={1,1,1};
 float arr1[3]={1.0,1.0,1.0};
 double arr2[3]={1.0,1.0,1.0};
 cout<<sizeof(arr)<<" "<<sizeof(arr1)<<" "<<sizeof(arr2)<<endl;
 cout<<sizeof(arr[0])<<" "<<sizeof(arr1[1])<<" "<<sizeof(arr2[2])<<endl;

输出:

12 12 24
4 4 8

3.动态数组

但是当sizeof运算符用于动态数组,就很神奇。

 vector<int>arr1(1,0);
  vector<int>arr2(2,0);
  vector<int>arr3(3,0);
   cout<<sizeof(arr1)<<" "<<sizeof(arr2)<<" "<<sizeof(arr3)<<endl;

输出:

 24 24 24

可以看到不管vector有多少元素,输入都是24,为啥?

这是因为 vector 是C++标准库中的容器类,其内部实现了三个指针,

  • start;
  • finish;
  • end_of_storage;

分别代表头, 尾(实际使用), vector 存储尾部(占用的,通常大于实际使用),finish-start对应于size(),end_of_storage-start对应于capacity(),如下图所示:

vector 通过配置比其所容纳的元素所需更多的内存,即先预留足够空间,避免二次分配,从而提高 vector 的性能。

so,sizeof(vec)其实得到的是三个指针占用内存。在64bit系统中,一个指针占用8个字节。

4.结构体

结构体成员是按照定义时的顺序依次存储在连续的内存空间,但是结构体大小并不是所有成员大小之和。这涉及字节对齐的问题。

4.1 偏移量

偏移量指的是结构体成员地址与结构体地址的差值。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。

4.2 字节对齐

字节是计算机内存的基本单位,但是并不是逐个字节存取,而是一次性存取4字节(32位系统),8个字节(64位系统),这样子也对访问地址做了限制,它必须是4,8的倍数。

如果数据地址不是4,8倍数会怎么样?

考虑64位系统,若没内存对齐规则,如果你的数据地址在0x0001-0x0008,因为地址不是0x0000开头,所以只能分别在0x0000-0x0007和0x0008-0x0015去两次数据,然后剔除多余数据,再把结果返回给你,这样子使得IO变慢。因为计算机CPU速度远远快于内存读写速度,所以减少内存访问次数是提升执行速度的关键。

按照对齐规则存取数据,将数据放在0x0000-0x0008,则可一次性取出,减少访问次数,提升性能。

以下引用于C/C++内存对齐详解

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。gcc中默认#pragma pack(4),可以通过预编译命令#pragma pack(n),n = 1,2,4,8,16来改变这一系数。

有效对其值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。

字节对齐规则如下

1.第一个结构体成员的地址偏移量为0,以后每个成员偏移量都是成员大小或者有效对齐字节数的最小值的整数倍。如有需要编译器会在成员之间加上填充字节。

2.结构体总大小是有效对齐值的整数倍。如有需要编译器会在最末一个成员之后加上填充字节。

举几个例子

#例1
struct stru 
{  
int a;  
char b;  
int c;  
}

例1,a偏移量为0,占用地址空间为0-3,然后b偏移量为4(成员的大小<有效对齐字节),占用地址空间为4,c偏移量不为5,而是8,占用地址空间为8-11,占用了12个字节,又是有效对齐值的整数倍。

#例2
struct stru 
{  
char a;  
int b;
int c;  
}

例2,a偏移量为0,占用地址空间为0,然后b的偏移量也不能是1,而是4,b占用的地址空间为4-7,c偏移量为8,占用地址空间为8-11,占用了12个字节。

#例3
struct stru 
{  
int a;  
char b;  
char c;  
}

例3,a占用4个字节,地址为0,b偏移量为4(成员大小<有效对齐字节),占用地址空间为4,c偏移量为5(成员大小<有效对齐字节),所以共5个字节,但是需要填充3个字节,所以例3结构大小为8。

#例4
struct stru 
{  
char a;
int b;  
char c;  
}

例4,a的偏移量为0,占用地址空间为0,但是b的偏移量不能是2了,应该是4,占用地址空间为4-7,然后c偏移为8,共占用了9个字节,但是整个结构体成员大小为12。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章