美文网首页
探索结构体的内存对齐

探索结构体的内存对齐

作者: 我E上去就是AWAQAR | 来源:发表于2021-06-09 12:07 被阅读0次

     先上两个简单的结构体,思考:这两个结构体大小是不是一样?

    附上:各数据类型的字节长度

    运行以下代码,查看打印结果:

    这个结果有没有在意料之中,以64位系统为例,struct1存取的字节数: double为8 、char为1、int为4、short为2,这就奇怪了,为什么读取内存不是按字节大小一个个读呢?这样就是8 + 1 + 4 + 2 = 15,这样看来不是更加省内存吗?通过查阅资料发现,处理器一般会以2字节,4字节,8字节,16字节甚至32字节为单位来存取内存。以这个思路重新计算一下,double以8字节存取,char以2字节存取,int以4字节存,short以2字节存,这样就是8 + 2 + 4 +2 = 16,并不是24,反而是struct2的大小。有没有可能计算机有一种策略,为了不在各种字节存取反复横跳,例如一会4字节存取,一会2字节存取,如果这样做会导致计算机开销巨大,是不是他就会定下一种策略,统一一个字节去存取,比如统一使用8字节存取,那么4个类型就是8 * 4 = 32,这里似乎又超过24,那么很可能的是计算机既做到了不用反复横跳的存取,又实现了内存的节省,究竟是怎么回事呢?

    猜测1:结构体是不是将第一个成员变量作为首地址先存取了,然后后续的成员,再按谁最大,就以多少字节存取?那么来算一下:

    double : 8   ,后面3个成员分别是 char int short , int占4个字节,所以后面以4字节读取,则通过计算得出

    8 + 4 + 4 + 4 = 20 ,还是不对。

    猜测2:第一个成员变量作为首地址先存取,后续成员的存取是不是和当前读取到的位置存在倍数关系,再进行一次计算

    double   : 8       【0 ~  7】

    char       : 1      【8】 有倍数关系

    int          : 4            (9 , 10 , 11 ) 无倍数关系  【12】有倍数关系,从这开始读4位就是【12 13 14 15】

    short     :  2         【16】有倍数关系 ,那就是【16,17】

    竟然是奇数!好像还是不对,难道他的总大小也会有倍数关系吗?看结果 24,确实是和里面的任意一个成员都有倍数关系,那么我是不是可以合理猜测,当内存计算出的结果和里面的成员变量没有倍数关系时,他会自动补齐后续内存以达成倍数关系。从17 到 24之间 ,也只有24和所有成员变量有倍数关系,只要总大小和里面最大的成员成倍数关系,那么与其他的都是倍数关系,这也是为什么不是20,而是24.以这种思路计算struct2

    double  : 8    【0 ~  7】

    int         : 4     【8 9 10 11】

    char      : 1     【12】

    short     : 2      【 14  15 】

    这里只读取到15,和 8 并不存在倍数关系,往后再读一位 那么就是 16

    我们再写多几个结构体试试

    计算struct 4:

     char      : 1    【0】

     char      : 1    【1】

     short     : 2    【 2  3 】

     int         : 4    【4 5 6 7】

    最后补齐结果为 : 8 ,是4的倍数

    计算struct 5

    int           4      【0 1 2 3】

    double    8      【8 9 10 11 12 13 14 15】

    long       8       【16 17 18 19 20 21 22 23】

    short      2       【24 25】

    最后同样要补齐结果为: 32  , 是 8的倍数

    打印验证:

    继续往下研究,如果结构体里也有结构体,如下图,结构体3包含了结构体5

     我们依旧按照前面的方法计算前5个成员

    double      8       [ 0  ~ 7]

    int             4       [8 ~ 11]

    char          1       [12]

    short          2      [14 15]

    int              4      [16 ~ 19]

    那么问题来了,我们已知struct5是32,那他是从32开始,然后直接32 + 32等于64呢?还是需要从结构体5内部开始存呢?如果从结构体5内部的话,那么接着上面计算结构体5内部:

    int           4    [20 ~ 23]

    double    8   [24 ~ 31]

    long        8   [32 ~ 39]

    short       2   [40 41]

    最后补齐倍数那就是8的倍数,往后存取就是48,

    打印结果:

     结果真的打脸,既不是64也不是48,如果计算内部时,不是以第一个成员的倍数开始,而是以最大的成员的倍数开始,  结果又会怎样呢?接着计算:

    int           4    [24 ~ 27]

    double    8   [32 ~ 39]

    long        8   [40 ~ 47]

    short       2   [48 49]

    最后补齐:56

     我的天,还真的是这样 ?为了进一步验证,我把struct5换成struct4,计算出的结果是32,大家可以尝试一下

    结论:

    关于结构体内存对齐,我得出几点原则:

    1.从第一个成员开始,首地址为0,后续成员的首地址需要和他们的大小成倍数关系。

    2. 最终大小如果和结构体里最大的成员无法成倍数关系,必须从当前地址继续往后偏移,直到地址和该成员成倍数关系,那么当前的地址就是结构体最终大小。

    3.如果是结构体嵌套结构体,计算大小过程并不是单一的把结构体大小加上其他成员变量,而是以结构体中内部最大的成员来找到和该成员对应的地址,然后再根据 1,2点进行运算,最终得出结果。

    探索收获:
    为什么要进行结构体对齐?

    从文章开头举的两个结构体例子中,我们可以知道,即使结构体里面的内容相同,但是大小确不是一样。通过探索结构体对齐,我明白在设计结构体中,一个好的结构体,往往能做到存取过程中,既节省空间,又能节省时间,比如例子中结构体2就比结构体1节省了8个字节,在文章上面计算struct1过程中,我们可以在计算中知道,结构体1,既要空出多余的空间,又要为了节省存取时间去补上了多余的空间,比如17到24这部分空间就是浪费了,而结构体2就没有这方面问题,从对比发现,似乎在设计结构体时,成员较小的尽量放到一起的话,会更省空间。虽然结构体内存对齐是为了用空间换取时间,但是我们作为开发者,也是可以通过巧妙的设计去帮助结构体节省空间。

    相关文章

      网友评论

          本文标题:探索结构体的内存对齐

          本文链接:https://www.haomeiwen.com/subject/bwjjeltx.html