OC alloc底层初探

188 阅读2分钟

由于正常途径下我们能看到的alloc方法有限,要研究它的底层实现,我们需要先获取到objc的底层源码.

objc源码可以通过苹果opensource网站获取:

opensource.apple.com/source/objc…

源码的编译参考Coici老师的文章 juejin.cn/post/684490… 来探究OC方法的底层实现.

alloc 方法

alloc是我们最常见的方法,那么我们使用alloc方法主要是做了什么呢?主要就是用来开辟内存空间,我们通过如下方法来看一下:

可以发现p1,p2,p3都指向了相同的地址空间,也就是说主要是alloc方法开辟了内存空间,init方法并没没有新开辟内存空间,接下来我们再来看一下alloc方法是如何来开辟和分配内存空间的:

通过下载objc源码以及源码编译器调试,可以发现alloc内部的方法调用顺序是:

alloc -> _objc_rootAlloc -> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone 或者  alloc -> _objc_rootAlloc -> callAlloc -> objc_msgSend

负责内存开辟与分配的主要是方法 _class_createInstanceFromZone

苹果内存地址最新版本采用的是16字节对齐方式:

static inline size_t align16(size_t x) {    return (x + size_t(15)) & ~size_t(15);}
  1. size = cls->instanceSize(extraBytes),这个方法的作用是计算出需要的内存空间大小

2) obj = (id)calloc(1, size) 这个方法就是去开辟size大小的内存区域,返回指向obj这块内存的指针.

  1. obj->initInstanceIsa(cls, hasCxxDtor),该方法的作用是将开辟的内存关联到相应类.

init方法

- (id)init {    return _objc_rootInit(self);

}
id_objc_rootInit(id obj){   // In practice, it will be hard to rely on this function.   // Many classes do not properly chain -init calls.
    return obj;
}

可以看到,init方法只是返回了alloc得到的obj地址,所以开始的示例中,p1、p2、p3指向的指针都是相同的.

new方法

+ (id)new {    return [callAlloc(self, false/*checkNil*/) init];}

new方法调用了callAlloc方法,这只是上面alloc方法调用步骤中的一个,所以new是不能等同于alloc的,不建议直接调用new方法,主要原因是它没有办法调用重写自定义的init方法.

new 方法实现原理:
//1,给对象分配内存空间地址        
//2,给对象完成默认的初始化操作        
//3,返回对象空间地址给对象指针