[iOS 理解] instanceSize

class_ro_t 中的 instanceSize

编译器把某个类的 OC 代码转为 C 代码时,子类结构体第一个变量,是父类结构体:

struct Child {
    struct Parent parent_ivars;
    int child_ivar; 
}; 

所以在内存布局上相当于把父类变量及当前类变量都放在一起,然后按照 C 结构体大小规则计算:
1 结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节
2 结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节
实际在计算 class_ro_t 中的 instanceSize 时,并没有遵守规则2,即最后不用补齐。
计算例子 (加号左边代表父类成员大小,最终父类是 NSObject,只有一个长度为8 的 isa)
8+1 = 9
8+1+4+1 = 8+4+4+1=17
8+1+1+8+1 = 8+ 8 +8+1 = 25
怎么知道没有遵守规则2 呢,这个数据是怎么来的呢,我用很笨的方法测试了一下:

   		id cls = MyClass.class; // 随便的类
        void *p1 = (__bridge void *)cls;
        uintptr_t * p2 =(uintptr_t *) p1;
        uintptr_t * p3 = p2 + 4; // objc_class::bits 的地址
        uintptr_t * p4 = (uintptr_t *)(*p3 & 0x00007ffffffffff8UL);
        // p4 is class_rw_t* 
        uintptr_t *p5 = (uintptr_t *)(*(p4 + 1));
        // p5 is class_ro_t*
        uint32_t instanceSize = *((uint32_t *)p5 + 2);
        // 这样就可以直接打印出 instanceSize 了
        // 通过对 MyClass 变量设计,可以验证 instanceSize 规则

unalignedInstanceSize

即 ro->instanceSize。

alignedInstanceSize

对 unalignedInstanceSize 实施规则2,即得到。
例如 9 变 16,17 变 24,25 变 32,目前总是 8 的倍数:因为必有 isa 是 8 字节,要补齐。

class_getInstanceSize

即 alignedInstanceSize。

class_createInstance

size_t instanceSize(size_t extraBytes);
用于为实例分配空间,不是实例大小,原注释是
// CF requires all objects be at least 16 bytes.
即使 alignedInstanceSize 是 8,也要分配 16 字节空间。
为什么要求至少 16 字节呢,我觉得可能是归因于操作系统堆内存的实现 :

操作系统设计堆内存时,arena 最小规格是 一个内存块 16 字节。
事实也是这样,malloc 族系统调用,即使参数只写 1 字节,也会申请 16 字节内存,提供的规格假设依次是 16,32,64,128…,申请 65 字节内存就会实际申请 128 字节空间。
因此 runtime 为对象申请内存时,干脆就设置必须申请 16 字节及以上。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值