一、前言
作为一名白发且秃顶的iOS程序猿,几乎每天都是在创建对象(程序猿不担心找不到对象,想要对象alloc或是new一个就可以了),一行代码解决了,但是alloc底层究竟做了什么,今天大家就跟随本猿初探下alloc底层流程吧。
二、准备工作
1.下载源码objc4,下载最新版即可。
2.编译源码(开源库下载下来基本各种编译失败,需要自行修改相关配置,由于不在本篇范畴,这里略过)
三、3种底层探索分析方式
1.断点调用alloc方法
在需要调试的alloc地方断点,当代码执行到断点处,按住control + step into(单步)进入即可进入到汇编代码部分,如图:
2.符号断点
从上一步断点alloc进入得知之后进入objc_alloc方法,把objc_alloc添加符号断点如下:
3.汇编方式
当断点停留在alloc时,选择Xcode -> Debug -> Debug Workflow -> Always Show Disassembly进入汇编找到objc_alloc方法,操作如下图:
四、源码调试探索
根据源码编译工程,断点进入alloc调试,流程如下:
1.首先会进入objc_alloc方法
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
2.接着第一次进入callAlloc
static ALWAYS_INLINE id
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));
}
3.接着通过objc_msgSend进入到alloc方法
+ (id)alloc {
return _objc_rootAlloc(self);
}
4.进入_objc_rootAlloc方法
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
5.第二次进入callAlloc方法
static ALWAYS_INLINE id
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));
}
6.进入_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);
}
7.进入_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;
size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
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);
}
8.进入alloc核心三步1-instanceSize,计算开辟内存空间所需的大小
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
9.进入alloc核心三步2-calloc,开辟内存,返回地址指针
10.进入alloc核心三步3-initInstanceIsa,初始化指针,和类关联起来
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
附上调用流程图如下:
五、总结
alloc 主要作用就是向系统申请开辟内存,通过isa指针与类进行关联。
著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处,谢谢。