OC 底层探索 01、如何探索底层 + alloc 做了什么

本文介绍 如何探索 alloc 和 alloc 做了什么?

objc 可编译源码 

从最简单的代码开始:

    MyPerson *p1 = [MyPerson alloc];
    MyPerson *p2 = [p1 init];
    MyPerson *p3 = [p1 init];
    
    NSLog(@"%@ - %p - %p",p1,p1,&p1);// p1 - 对象 - 指针
    NSLog(@"%@ - %p - %p",p2,p2,&p2);
    NSLog(@"%@ - %p - %p",p3,p3,&p3);

打印结果如下:

p1/p2/p3:对象是同一个MyPerson,指针指的同一个对象,指针地址不同。且其指针地址相差 8 字节,为什么呢?

alloc 做了什么?我们点击 alloc 无法查看实现,只能停留在 NSObject.h 中?

一、如何查找实现ku?

查找实现库

1、符号断点:

run: --> [NSObject alloc] --> libobjc.A.dylib

2、普通断点

按住:control + step into -->

添加符号断点:objc_alloc --> libobjc.A.dylib

3、汇编查看

debug->debug workflow -> always show disassembly

运行:

control + step into -->  如下图 --> 添加 符号断点 objc_alloc --> libobjc.A.dylib

objc 源码下载 - 地址:最新版本 objc4-781

二、进入源码 -- 流程分析

打开下载的源码文件,由 C C++ 汇编共同编写。

1、源码分析

1.1)alloc 入口:

 

我们通过点进去,发现:

_objc_rootAlloc --> callAlloc --> _objc_rootAllocWithZone / objc_msgSend 2者走谁?

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));
}

可通过:回到 demo,添加符号断点:_objc_rootAlloc / callAlloc / _objc_rootAllocWithZone --> 运行

跟随断点,可知 alloc 走 _objc_rootAllocWithZone:

 

1.2)开辟空间 _objc_rootAllocWithZone()

id
_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() --> 源码中 3 个方法(标红位置)

_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;
    // 1: 算出要开辟多少内存
    size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (zone) {// zone 已经废弃不走它 直接走 else
        obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
    } else {
        // 2: 去申请内存,返回 地址指针
        obj = (id)calloc(1, size);
    }
    if (slowpath(!obj)) {
        if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
            return _objc_callBadAllocHandler(cls);
        }
        return nil;
    }

    // 3: 指向内存的地址指针 和 cls 关联 起来
    if (!zone && fast) {
        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);
}

思考,是否可以直接运行源码走进方法进行调试呢?

--> objc 源码编译调试 配置方法

配置成功后,run。

2、实际运行分析

2.1)开辟多少内存空间 instanceSize()

align16() --> size + 0 - 8 = 8; // size = 16

static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

字节对齐 (针对对象)-- 最新的是16字节对齐,苹果之前的对齐方式是8字节对齐。16字节更加安全,预留空间更多,不易产生野指针等。

每个对象都有继承自NSObject 的 isa,一个指针8字节。

2.2)申请开辟内存空间 calloc()  -->  2.3)内存指针和 类 cls 绑定 initInstanceIsa()

三、init 和 new

init:

 

构造方法(工厂),用来给我们自定义开发 - 重写。

new: --> alloc 的 callAlloc --> [MyPerson new];  ==》相当于 [[MyPerson alloc] init];

但,我们 init 重写的一些方法,在new是无法实现的。 <-- 不同之处

以上。

tip:slowpath / fastpath 是什么? -- 编译器优化

例如一些中间过程编译直接优化掉,节省时间,优化性能

如上图,release 是 Feastest,Smallest, 发包苹果也会帮我们进行优化。 

运行:

我们将 debug 也改成 fastest,smallest,再次运行,可看到中间编译过程已被优化掉:

 

posted @ 2020-09-08 10:11  张张_z  阅读(356)  评论(0编辑  收藏  举报