探索之前我们先来看个例子

如上图所示,用了%@和%p,打印输出对象,结果输出的同样的结果,但是打印输出&对象就不一样了呢?
cars1对象用了alloc,开辟了内存空间,cars2和cars3是用cars init的结果,三个指针对象,指向了同一个块内存空间,但是指针对象本身的地址是不一样的。这就类似办公室里面共有一台打印机,但是拥有打印机的每个个体都是不一样的。&取地址
- alloc开辟内存空间,而init不会开辟
- 指向同一块内存空间的指针,指针本身的地址不一定相同
- 栈内存是连续开辟的,指针本身所占的字节为8bit
一、alloc的流程
1.1初步流程

- 我们先下载个定位objc源码,可以下载最新的源码objc4-781.
https://opensource.apple.com/tarballs/objc4/
15995363336390.jpg
- 打开源码,全局搜索下alloc{
objcAlloc.gif
1.2完整流程
准备一份含有objc源码的项目,链接https://github.com/zhaimengting/objc4
接着上面的流程呢,我们再深入了解下。
_objc_rootAllocWithZone深入是什么呢?

此时流程图为

1.2.1 cls->instanceSize 开辟多少内存
双击cls->instanceSize,选择Jump to definition
进入
size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
- if(fastpath(cache.hasFastInstanceSize(extraBytes)))
为ture时,返回cache.fastInstanceSize(extraBytes),进入fastInstanceSize(extraBytes)
size_t fastInstanceSize(size_t extra) const
{
ASSERT(hasFastInstanceSize(extra));
if (__builtin_constant_p(extra) && extra == 0) {
return _flags & FAST_CACHE_ALLOC_MASK16;
} else {
size_t size = _flags & FAST_CACHE_ALLOC_MASK;
// remove the FAST_CACHE_ALLOC_DELTA16 that was added
// by setFastInstanceSize
return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
}
}

extra值为0,返回align16(size + extra - FAST_CACHE_ALLOC_DELTA16)

static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
size_t x = 32;
32(二进制) =0000 0000 0010 0000;
15(二进制) =0000 0000 0000 1111;
47(二进制) =0000 0000 0010 1111;
~15(二进制) =0000 0000 1111 0000;
47&(~15) =0000 0000 0010 0000;
size_t align16主要作用是16位内存对齐
1.2.2 calloc 开辟内存的地址
obj = (id)calloc(1, size);
void *calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2);
- size_t __count 开辟内存空间的个数
-
size_t __size 所开辟内存的大小
15996343883250.jpg
1.2.3 obj->initInstanceIsa 将对象的isa指针指向开辟的内存空间地址

总结上面内容入下表
cls->instanceSize | 先计算出需要的内存空间大小 |
---|---|
calloc | 向系统申请开辟内存,返回地址指针 |
obj->initInstanceIsa | 关联到相应的类 |
二、init的探索
在含有alloc函数的NSObject.mm中搜索init{
+ (id)init {
return (id)self;
}
构造方法返回self。
那么与new又有什么区别呢?
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
实质上没有什么区别,但是有时候我们会在类里面重写init方法,如果用new方法的话,不会走init重写方法,尽量不用new。
网友评论