• 01-01 iOS内存对齐、内存对齐算法


    内存对齐规则

    1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第

    一个数据成员放在offset为0的地方(即首地址的位置),以后每个数据成员存储的起始位置要

    从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,

    结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存

    储。

    2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从

    其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b

    里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

    3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大

    成员的整数倍.不足的要补⻬。

    上面的规则真书面化,看了几遍 翻一下

    • 结构体或者联合 的第一个数据成员放在offset 为0 的地方(即首地址);

    • 从第二个数据成员开始,存储的起始位置是该成员大小的整数倍(比如int为4字节,则该成员的存储位置的其实地址是4的整数倍。(取 默认对齐数 和该成员对齐数的较小值 )

    • 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

    • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

    • 最大对齐数就是对大的成员大小

    struct  WQPeople1{
        char a;     // 1 + 7
        double b;   // 8
        int c;      // 4
        short d;    // 2 + 2
    }myPeople1;
    
    struct  WQPeople2{
        double b; // 8
        int c;    // 4
        char a;   // 1
        short d;  // 2 + 1
    };
    
    

    WQPeople1 a 1位 b8位 > 8 所以 a 补 7位 b单独8位

    c 4位 d 2位 < 8 所以补 2位

    WQPeople2 b 8位 > 8

    c 4位 a 1位 d 2位 < 8 所以补 1位

    struct X1
    {
        char c1;
        int i;
        char c2;
    };
    /*
     为什么是 12 ?
    假设首地址为 px0;  0x7ffee2553170
      char c1  1个字节  首地址为px0        使用1个字节但是占用4字节          符合偏移量为0的地方开始;占用4 是因为下个成员取4的整数倍
       int i   4个字节, 地址为px0 + 4     占用4个字节                    符合开始地址必须是该成员大小的整数倍
      char c2  1 字节    地址为px0 + 8     1个字节
                                          共9 个字节;                  符合 总大小应该为最大成员
     
     p pp
     (X1) $5 = (c1 = 'a', i = 14, c2 = 'b')
     
     61 00 00 00 0E 00 00 00            61 =》 16 * 6 + 1 = 97      E=》 14
     62 00 00 00 00 00 00 00            61 =》98
    
     
     */
    
    struct X2
    {
        char c1;
        char c2;
        int i;
    };
    /*
     首地址 0x7ffee56ef168
     61 62 00 00 0E 00 00 00
     
     
        char c1;              从0 开始  占   1 字节
        char c2;  大小为 1  故  从 1开始  占 1字节
        int i;  大小为 4 字节 故 从4的倍数开始  从4 开始 占用 4个字节
     最大对齐数是 4    一共使用了 1 + 1 + [2]  + 4 = 8      8 是4的倍数  故占用8 个字节
     
     最大对齐数是最大成员的对齐数,这个是前面算过的(成员大小和默认对齐数取小)
     */
    
    
    struct X3
    {
        double d;
        char c;
        int i;
    };
    /*
     
     0x7ffee7614158
     
     CD CC CC CC CC CC 24 40
     64 00 00 00 14 00 00 00   -> b    14
     
        double d;   8
        char c;     1 +  [3]
        int i;    从4的倍数开始 所以上面 补 3    占用 4个
     共 8 + 1 +【3】 + 4 =  16 最大对齐数 min(默认对齐数 ,成员中自身最大对齐数)  -》16
     
     */
    
    str``uct X4
    {
        char c1;
        struct X3 x3;
        double d;
    };
    /*
     
     61 00 00 00 00 00 00 00   a
     CD CC CC CC CC CC 24 40   10.4
     62 00 00 00 0E 00 00 00    b   14
     33 33 33 33 33 33 25 40
     
       struct X4 pp4 = {'a',{10.4,'b',14},10.6};
     
     char c1;           1字节  +【7】
     struct X3 x3;   x3的最大对齐数是它min(内部成员变量的最大对齐数,默认成员对齐数) = 8  占用了 8 + 1+【3】 + 4 = 16
     double d;     占用8个
     
     共  1+ 【7】 + 16 + 8个 = 32个
     */
    
    
     struct X1 pp = {'a',14,'b'};
        printf("X1 == %lu", sizeof(struct X1));
        struct X2 pp2 = {'a','d',20};
    
        printf("X2 == %lu", sizeof(struct X2));
        
        struct X3 pp3 = {10.4,'d',20};
        struct X4 pp4 = {'a',{10.4,'b',14},10.6};
    
        printf("X2 == %lu", sizeof(struct X2));
        printf("X3 == %lu", sizeof(struct X3)); //16
        printf("X4 == %lu", sizeof(struct X4));
    

    pp 内存图

    pp2

    pp3

    pp 4

    对齐算法

    _class_createInstanceFromZone ->

    size_t size;
    /// 设置开辟内存的大小
    size = cls->instanceSize(extraBytes);
    
    size_t instanceSize(size_t extraBytes) const {
      ...
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        /// 内存最少是16字节
        if (size < 16) size = 16;
        return size;
    }
    
     uint32_t alignedInstanceSize() const {
            /// 字节对齐
            return word_align(unalignedInstanceSize());
    }
    
    
    

    注意点class_getInstanceSize实际占用的大小 没有size < 16 size = 16;

    NSLog(@"%zu--%zu",
       class_getInstanceSize([person class]),
       malloc_size((__bridge const void *)(person))
    ); 
    // 8 --16
    
    size_t class_getInstanceSize(Class cls)
    {
        if (!cls) return 0;
        return cls->alignedInstanceSize();
    }
     uint32_t alignedInstanceSize() const {
            /// 字节对齐
          return word_align(unalignedInstanceSize());
    }
    
    
    #   define WORD_MASK 7UL
    static inline size_t word_align(size_t x) {
        return (x + WORD_MASK) & ~WORD_MASK;
    }
    
     #ifdef __LP64__
    #   define WORD_SHIFT 3UL
    #   define WORD_MASK 7UL
    #   define WORD_BITS 64
    #else
    #   define WORD_SHIFT 2UL
    #   define WORD_MASK 3UL
    #   define WORD_BITS 32
    #endif
     
     return (x + WORD_MASK) & ~WORD_MASK;// 返回8的整数倍
    
     
        /*
         获取大于等于某一个数的最小8倍数  比如 15  -》 8 ;  16 - 》 16  ; 17 -》16
         例子1:   (8 + 7) & ~7
         
          7   0000  0111
         ~7   1111  1000
         15  &0000  1111
         --------------------
              0000  1000 = 8
    
        例子2: ( 9 + 7) & ~7
              
           7   0000 0111
          ~7   1111 1000
        & 16   0001 0000
        -----------------------
               0001 0000    16
         
    结论   (x + 2^n) & ~2^n -> m(m大于等于x 且是2^n的最小倍数)
    
    //另外一种获取大于等于某一个数的最大的那个8的倍数
      k =  x >>3 
      q =  <<3 
        
      15    0000  1111   
            0000  0001
            0000  1000  
        8
        
    
  • 相关阅读:
    angualrjs2教程
    需要关注的技术
    webstorm 2016
    Java内存泄露分析和解决方案及Windows自带查看工具
    2018-6-21-随笔-WEB应用程序
    2018-6-20-随笔-SQL Server中乱码
    2018年6月15日随笔--统计图
    2018-6-12随笔-类库
    2018-6-11随笔-返回值-密钥
    vs各种版本
  • 原文地址:https://www.cnblogs.com/xiaowuqing/p/14027700.html
Copyright © 2020-2023  润新知