zoukankan      html  css  js  c++  java
  • 内存对齐

    为什么要内存对齐

    cpu在读取内存时是一块一块进行读取的,块的大小可以是2,4,8,16(总之是2的倍数)。

    64位系统默认是8字节,块的大小也可以自己用宏定义:#pragma pack(nSize);

    CPU和内存IO的硬件限制导致没办法一次跨在两个数据宽度中间进行IO。

    假如对于一个c的程序员,如果把一个bigint(64位)地址写到的0x0001开始,而不是0x0000开始,那么数据并没有存在同一行列地址上。因此cpu必须得让内存工作两次才能取到完整的数据。效率自然就很低

    举例来说:如果一个变量int 的起始地址偏移是1,那么CPU要取这个地址上的数据,需要取两次。

    如图,cpu按四字节读取,第一次读取0x0 ~ 0x3,

     cpu第二次读取0x4 ~ 0x7,这时cpu才能读到这个int的值。

    如果内存对齐了呢,就如下只需一次读取:

    内存对齐的规则

    1:数据成员对齐规则:结构体或联合体(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员
    的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。
     
    2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
     
    3:收尾工作:结构体的总大小,也就是sizeof的结果。必须是其内部最大成员的整数倍.不足的要补齐。

    内存大小的计算

    因为内存对齐的存在,申请的内存往往会比实际使用的内存大,比如

    typedef struct {
        int a;             //4字节
        double b;      //8字节
        short c;         //2字节
    }A;
    
    typedef struct {
        int a;             //4字节
        short b;         //2字节
        double c;      //8字节
    }B;
    
    sizeof(A)=24
    sizeof(B)=16


    上面两个结构体,理论上来说它们是一样大小的,但是当我们sizeof(A)=24,sizeof(B)=16。

    分析一下:对结构体A来说,a占4个字节,占从0 ~ 3的字节,b是double类型占8个字节,占从8 ~ 15的字节,c占两个字节,

    从16 ~ 17的字节。 对结构体B来说,a占4个字节,从0 ~ 3,b占两个字节从4 ~ 6;c占8个字节从8 ~ 15。当然上面的分析是针对gcc编译器的,不同的编译器有不

    同的对齐规则。

    扩展1:如果不强制对地址进行操作,仅仅只是简单用c定义一个结构体,编译和链接器会自动替开发者对齐内存的。尽量帮你保证一个变量不跨列寻址。

    扩展2:其实在内存硬件层上,还有操作系统层。操作系统还管理了CPU的一级、二级、三级缓存。实际中不一定每次IO都从内存出,如果你的数据局部性足够好,那么很有可能只需要少量的内存IO,大部分都是更为高效的高速缓存IO。但是高速缓存和内存一样,也是要考虑对齐的。



    参考博客:https://www.jianshu.com/p/cc0d1d627b73        https://www.jianshu.com/p/37409be16a37

  • 相关阅读:
    图灵测试
    百度面试题
    【javascript每日一练】- 插入排序
    各种排序讲解
    【javascript每日一练】- 多维数组
    不用JQuery,原生Javascript实现Ajax功能及相关知识点
    【javascript每日一练】- 无序数组排序
    前端面试题
    前端重构面试题
    面试题
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12722800.html
Copyright © 2011-2022 走看看