博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2020-11-23 22:47  肖无情  阅读(245)  评论(0编辑  收藏  举报

内存对齐规则

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