1.OC底层-alloc探索

1.OC底层-alloc探索

三种调试方法

  • 1.符号断点

    • 1.打上断点

    • 2.按住control键 点击step into

    • 3.即可查看底层调用方法

    • 4.由于无法继续stepinto查看objc_alloc 需要手动添加断点调试

    • step into 即可找到底层源码 libobjc.A.dylib`objc_alloc:

  • 2.查看汇编调试

    • 打开汇编调试,即可在断点处进入汇编查看

    • 2.也可在汇编方法前打上断点,再step into

  • 3.当无法确定调用了什么方法时但是至少知道alloc

    • 1.写上方法名打上断点

alloc的源码分析

  • 源码怎么编译成功的什么的我就不太懂了给个链接

juejin.cn/post/697132… 大家可以看看这位怎么做的。

  • 1. LGPerson *p = [LGPerson alloc] ;
  • 2.+ (id)alloc {return _objc_rootAlloc(self);}
  • 3
_objc_rootAlloc(Class cls){    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);}
  • 4.进入这里思考是先调用 _objc_rootAllocWithZone 还是 调用 objc_msgSend

  • 5.将_objc_rootAlloc、callAlloc、_objc_rootAllocWithZone,下好符号断点,并打开汇编调试。查看得知先调用的时_objc_rootAllocWithZone再调用objc_msgSend

  • 6.再往下走就可以查看_objc_rootAllocWithZone

  • 7.源码查看 LGPerson类

  • 9.进入 obj = (id)calloc(1, size);
  • 10.进入下一步后 发现地址发生改变

  • 11.地址与类进行绑定
    • hasCxxDtor 绑定方法和函数
  • 12.返回出去了这个对象

开辟内存流程

  • 对象的内存大小取决于成员变量属性
  • 计算对象内存大小

  • 缓存

  • May be unaligned depending on class's ivars.
  • 类的IVAR可能未对齐。

  • Class's ivar size rounded up to a pointer-size boundary.
  • 类的ivar大小向上舍入为指针大小边界。
  • 说明这里对类的成员变量做了 字节对齐

  • 得到的结果为 8 的整数倍 向上取整
- 假如 x = 8- X+7 & ~7  -> 8 + 7 & ~ 7- 8 :  0000 1000               - 7 :  0000 0111- ~7 : 1111 1000- & 运算 相同为1 不同为0- 15   0000 1111- &    1111 1000----------------       0000 1000       - 得到结果为 8       - 假如 X = 9       - 9 :  0000 1001               - 7 :  0000 0111- ~7 : 1111 1000- & 运算 相同为1 不同为0- 16   0001 0000- &    1111 1000----------------       0001 0000         - 得到结果为 16       我认为可以理解为 X / 8  = 商 --余数- 当有余数时 为 (商+1)*8- 没有余数时 为  商 * 8 位运算 >> 3 右移 3位 即 / 1000 如 15 : 0000 1111 >> 3 = 0000 0001 111      << 3 左移 3位 即 * 1000 如 15 : 0000 1111 << 3 = 0111 1000      所以 15 右移 3位 后 再 左移 3 位 得到了  0000 1000 为 8 
  • 对象的内存大小由 isa (8字节) + 成员变量的大小
  • 同时这里规定了如果内存大小小于16则设置为16

  • 字节对齐 8 字节 64位 为 8字节

  • 内存对齐 16 字节

  • 通过isa 获取类 地址

  • isa & isa_mask

整理流程

  • 1._objc_rootAlloc 传入 类
+ (id)alloc {    return _objc_rootAlloc(self);}
  • 2.callAlloc 这里有个同时传入 false 和 true
_objc_rootAlloc(Class cls){    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);}
  • 3._objc_rootAllocWithZone 出入了 cls
callAlloc(Class cls, bool checkNil, bool allocWithZone=false){#if __OBJC2__  //是否有可用的编译器优化//slowpath 大概率为假//fastpath 大概率为真//提升编译效率。if (slowpath(checkNil && !cls)) return nil;    //判断一个类是否有自定义的 +allocWithZone 实现,没有则走到if里面的实现    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));}
  • 4._class_createInstanceFromZone
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused){    // allocWithZone under __OBJC2__ ignores the zone parameter    return _class_createInstanceFromZone(cls, 0, nil,                                         OBJECT_CONSTRUCT_CALL_BADALLOC);}
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,                              int construct_flags = OBJECT_CONSTRUCT_NONE,                              bool cxxConstruct = true,                              size_t *outAllocatedSize = nil){    ASSERT(cls->isRealized());    // Read class's info bits all at once for performance    bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();    bool hasCxxDtor = cls->hasCxxDtor();    bool fast = cls->canAllocNonpointer();    size_t size;    size = cls->instanceSize(extraBytes); //计算内存大小    if (outAllocatedSize) *outAllocatedSize = size;    id obj; //分配一块脏地址    if (zone) {        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);    } else {        obj = (id)calloc(1, size); //分配一块可以使用的内存空间    }    if (slowpath(!obj)) {        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {            return _objc_callBadAllocHandler(cls);        }        return nil;    }    if (!zone && fast) {        //将这块可使用的地址isa与cls类相关联        obj->initInstanceIsa(cls, hasCxxDtor);    } else {        // Use raw pointer isa on the assumption that they might be        // doing something weird with the zone or RR.        obj->initIsa(cls);    }    if (fastpath(!hasCxxCtor)) {        return obj; //返回对象    }    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;    return object_cxxConstructFromClass(obj, cls, construct_flags);}

//slowpath 大概率为假
//fastpath 大概率为真
//此处去掉slowpath和fastpath对代码逻辑没有丝毫影响,应该只是告诉编译器对代码优化,提升编译效率。

计算内存大小过程

  • 计算需要开辟多少的内存空间

  • 流程示意图

免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部