美文网首页
[[NSObject alloc] init]

[[NSObject alloc] init]

作者: _一叶孤帆 | 来源:发表于2021-01-27 18:21 被阅读0次

    示例代码:

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            NSObject *obj = [[NSObject alloc] init];
        }
        return 0;
    }
    
    

    思考1

    一个 NSObject 对象会占用多少内存空间

    思考2

    allocinit 分别进行了什么操作

    分析

    我们都知道 OC 是基于 C/C++ 语言来实现的,所以我们可以将我们的 OC 代码转成 cpp 文件来查看一下。

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o mainarm64.cpp
    

    运行成功之后会生成下面文件

    image.png

    在这个文件的最后我们可以找到我们的 main方法 和 NSObject 的定义

    int main(int argc, const char * argv[]) {
        /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
    
            NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
            
            /*
             NSObject *obj = objc_msgSend(objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
             */
        }
        return 0;
    }
    
    struct NSObject_IMPL {
        Class isa; 
    };
    

    源码分析

    我们可以看到在NSObject.mm 中如下定义:

    image.png

    可以看出,所有的创建方法都会触发 callAlloc 函数,而我们 init 只不过是在 callAlloc 之后调用了 init 方法

    image.png

    然后会在 callAlloc 方法中进入 _objc_rootAllocWithZone 方法

    image.png

    然后会调用 _class_createInstanceFromZone 方法

    image.png

    size = cls->instanceSize(extraBytes);这个方法就是为我们计算需要多少内存的方法

    image.png

    hasFastInstanceSize的作用就是判断能否快速查找需要开辟的内存空间大小(查找是否有缓存数据) 当无法进行快速查找的时候就会使用 alignedInstanceSize 进行计算,可以看到里面当 size 小于 16 时,size 是强制等于 16 的,所以我们可以认为我们最小对象计算的空间这里给的一定是 16

    image.png

    __builtin_constant_p 是GCC的内建函数 用于判断一个值是否为编译时常数,如果参数EXP 的值是常数,函数返回 1,否则返回 0

    此处计算出的值为 16 且会直接进入到 align16 的方法。

    _flags是chass_rw_t结构体中的属性,在初始化alloc方法时系统回调用objc_class结构体中的setInfo方法,并调用data->setFlags 方法为_flags进行了赋值

    x+size_t(15) & ~size_t(15): 将x与15相加,然后再和15按位取反的数进行按位与计算,示例如下, 令 x = 7:

    x  = 7    0000 0111
    15        0000 1111
    x + 15    0001 0110
    ~15       1111 0000
    
    x + size_t(15) & ~size_t(15)
    16        0001 0000
    
    image.png

    可以看出该算法是开辟的内存使用实际开辟的内存进行16的倍数扩容。

    当拿到计算出的内存空间时,然后进入 _class_createInstanceFromZone 中的 calloc 进行分配内存。

    然后调用 initInstanceIsa 进行 ISA 绑定

    image.png image.png image.png

    然后将构建好的 obj 进行返回。

    所以在此处我们可以确认我们的 NSObject 对象是分配了 16 个字节的内存。

    然后我们来看 init 操作,点击 init 会进入到下面方法

    image.png image.png

    所以我们可以看到 init 其实返回了对象本身,并没有任何操作。

    最后可以验证一下

    image.png

    资料

    iOS底层探索之alloc
    OC对象探究02:内存分析
    iOS底层原理 - alloc & init & new 详解

    相关文章

      网友评论

          本文标题:[[NSObject alloc] init]

          本文链接:https://www.haomeiwen.com/subject/wojwzktx.html