ios对象的底层探索(上)

  1. 常用指令

1. po:   为 print object 的缩写,显示对象的文本描述
2. bt:   打印函数的堆栈  
3. register read    读取寄存器
4. x/nuf 
    n表示要显示的内存单元的个数
    u表示一个地址单元的长度:
    取值范围: 
            b 单字节  
            h 表示双字节
            w 表示四字节
            g 表示八字节
    f表示显示方式:
    取值范围:
            x 按十六进制格式
            d 按十进制格式
            u 按十进制格式显示无符号
            o 按八进制格式
            t 按二进制格式
            a 按十六进制格式
            i 指令地址格式  
            c 按字符格式
            f 按浮点数格式

持续更新中...
复制代码
  1. 创建一个熟悉的对象

**2022-04-16 18:14:47.784118+0800 SXObjcDebug[27806:312258] <NYPerson: 0x100b39ba0>-0x100b39ba0-0x7ff7bfeff310**

**2022-04-16 18:14:47.784578+0800 SXObjcDebug[27806:312258] <NYPerson: 0x100b39ba0>-0x100b39ba0-0x7ff7bfeff300**
**2022-04-16 18:14:57.634432+0800 SXObjcDebug[27806:312258] <NYPerson: 0x100b39ba0>-0x100b39ba0-0x7ff7bfeff308**

复制代码

通过调试代码,我们发现p1,p2,p3都是打印内存0x100b39ba0&p1,&p2,&p3打印的是不一样的。 我们通过objc4-838.1 看看alloc,init 做了什么。(也可以通过符号断点跟踪Symbolic Breakpoint)

  1. alloc的流程图

通过调试验证:

+ (id)alloc {
    return _objc_rootAlloc(self);
}
id

_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

复制代码

然后我们进入了objc_alloc (那么这边有一个问题,alloc里面调的是_objc_rootAlloc。这是为什么呢,我们一步一步来。)

callAlloc中 ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc)) 消息转发到 alloc

static ALWAYS_INLINE id

callAlloc(Class cls, bool checkNil, bool allocWithZone=false)

{

#if __OBJC2__

    if (slowpath(checkNil && !cls)) return nil;

    if (fastpath(!cls->ISA()->hasCustomAWZ())) {

        return _objc_rootAllocWithZone(cls, nil);

    }

#endif

\


    // No shortcuts available.

    if (allocWithZone) {

        return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);

    }

    return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));

}
复制代码

第二次到了callAlloc 中执行_objc_rootAllocWithZone->_class_createInstanceFromZone 最后在_class_createInstanceFromZone进行内存分配。

  1. _class_createInstanceFromZone分析

我们看到了_class_createInstanceFromZone 中计算内存的方法 size= cls->instanceSize(extraBytes);

我们跟踪到具体计算方法:

根据cpu位数是32位64位计算。

如:(8 + 7) & ~7  8字节对齐,取8的整数倍
(8 + 7) >> 3 << 3
0000 1001 
&
1111 1000
0000 1000 = 8
复制代码

为什么是8位呢,用8字节取读不断变化的空间连续内存,空间换取时间。

  1. 通过struct 结构体分析内存对齐

下面我们通过计算 struct1,struct2,struct3 的字节数,验证字节对齐。

通过字节对齐算法,我们计算得出 struct1=24,struct2=16,struct3=48

验证输出:

总结

综上的现象,我们可知alloc()方法实现了对象的内存分配,内存对齐,将对象和类型绑定三个功能。

内存对齐实际案例

  1. Apple在64位下,对象内存对齐是16,结构体是8。
  2. 内存分配时,会根据属性或成员变量的类型length, 属性或成员的起始内存必须是该类型length的整数倍。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值