本文分析
NSObject
的alloc
和 自定义对象 的alloc
的执行过程
本次调试使用 objc4-781
》 1. NSObject 的 alloc
- 断点到 alloc 位置, 启动汇编调试
Debug
->Debug Workflow
->Always Show Disassembly
image.png
可以发现执行到符号断点objc_alloc
方法, 在NSObject.mm
中搜索到objc_alloc
方法, 点击进去,1728行找到该方法
image.png

-
关闭汇编调试
Debug
->Debug Workflow
->Always Show Disassembly
, 重新运行项目, 在1728行添加一个断点, 让程序进去断点1728行, 这是发现cls
就是我们NSObject
类
image.png
-
接着 执行
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
函数, 在1706行断点,会发现执行到这里
image.png
疑问1: 那么 _objc_rootAllocWithZone
到底做了什么??,接着向下走
_objc_rootAllocWithZone
-> _class_createInstanceFromZone
, 这时会发现对象的创建在这里完成
static ALWAYS_INLINE id
_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) {
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: 绑定到对应的类
if (!zone && fast) {
// 将cls类 与 obj指针(即isa)关联
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);
}
_class_createInstanceFromZone
函数做了三件事分别是 :
1. 要申请多大内存空间 (instanceSize)
2. 申请内存,创建对象 (calloc)
3. 关联绑定创建的对象 (initInstanceIsa)
执行到这里,在将NSObject 创建完成返回
疑问2:NSObject
对象为什么没有走 alloc
类方法,而是执行的objc_alloc
函数,带着这个疑问我们继续向底层探索

这部分需要通过 LLVM源码(即llvm-project) 来分析
- 在llvm源码中搜索
omf_alloc
找到tryGenerateSpecializedMessageSend
,表示尝试生成特殊消息发送Snip20200910_36.png
可以发现,如果调用NSObject的alloc
方法 会执行到EmitObjCAlloc
函数, 通过查找EmitObjCAlloc
可以发现,执行的是objc_alloc
Snip20200910_37.png
由此可以得出 NSObject中的alloc
会走到objc_alloc
,其实这部分是由系统级别的消息处理逻辑,所以NSObject的初始化是由系统完成的,因此也不会走到alloc的源码工程中。
》 2. 自定义对象MGPerson 的 alloc
断点到MGPerson的 alloc
位置, 启动汇编调试 Debug
-> Debug Workflow
->Always Show Disassembly


这时候会发现也执行了
objc_alloc
方法, 和NSObject
的流程一样是吧, 别着急慢慢向后看
-
关闭汇编调试
Debug
->Debug Workflow
->Always Show Disassembly
, 重新运行项目, 在1728行添加一个断点, 让程序进去断点1728行, 这是发现cls
就是我们MGPerson
类
image.png
-
继续执行代码,发现会走到
callAlloc
函数中的objc_msgSend
消息发送,通过sel
找到对应的IMP
执行类方法+ (id)alloc {}
image.png
-
断点到2321行,执行了 alloc 类方法,(自定义类MGPerson走了类方法, 上面分析的NSObject没有执行)

到这里就和alloc & init探索中的执行顺序一样了,
执行函数 _objc_rootAlloc
-> callAlloc
-> _objc_rootAllocWithZone
-> _class_createInstanceFromZone
, 到这里就和上面的NSObject
执行_class_createInstanceFromZone
一样了,对象创建的重要三步:
1. 要申请多大内存空间 (instanceSize)
2. 申请内存,创建对象 (calloc)
3. 关联绑定创建的对象 (initInstanceIsa)
总结: 自定义对象的执行顺序 objc_alloc
-> alloc
, 而NSObject只走了objc_alloc

网友评论