关于alloc
alloc是oc对象实例化方法,想必大家在日常工作中alloc已经写了无数次,例如:
LGPerson *person1 = [LGPerson alloc] ;
LGPerson *person2 = [[LGPerson alloc] init];
LGPerson *person3 = [[LGPerson allocWithZone:nil] init];
LGPerson *person4 = [LGPerson new];
复制代码
那么问题来了,这几种alloc有什么区别呢?
我们先说一下这几种分别做了什么,然后我们再来解析具体流程。
我们从下往上说:
- new方法等同alloc和init,alloc分配了内存,然后调用init初始化,new在分配内存后直接调用init进行初始化,一步到位
- 说起allocWithZone就要说一下NSZone,在苹果的官方文档中是这样介绍的:NSZone是apple用来说分配和释放内存的一种方式,它不是一个对象,而是使用c结构存储了关于对象的内存信息。allocWithZone方法是历史遗留问题,现在也不使用了,allocWithZone和alloc没有区别,等下在源码解析的也会看到
- 最后说下person1和person2,这两种的区别是,person1分配了内存没有初始化,而person分配了内存同时也完成了初始化
不难发现,这几种写法最后都和alloc方法离不开,那么我们现在来探索一下alloc做了些什么?
源码准备
- 苹果的openSource的opensource.apple.com/ 有开源的Mac系统下Objc的源码下载
- 源码的编译可以参考Cooci先生的文章macOS 10.15下objc4-779.1源码编译调试
源码跟踪
- 我们可以直观的看到alloc内部调用了_objc_rootAlloc,allocWithZone内部调用了_objc_rootAllocWithZone,然后我们继续跟踪看下这两个函数内部的调用
- 在这里就可以看到为什么说alloc和allocWithZone没有什么区别,因为它们内部都调用了callAlloc函数
那么我们再看一下callAlloc最终内部实现了什么
- 断点调试调用了_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) {
// 2;allocWithZone指定内存池
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: 将 cls类 与 obj指针(即isa) 关联
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);
}
复制代码
- 现在可以看到在这个方法中计算所需内存大小,以及字节对齐,调用calloc分配内存,最后通过initInstanceIsa将cls和isa关联起来
- 这样整个流程走完,alloc对象创建分配完成
总结
现在可以梳理一下整个流程
alloc->_objc_rootAlloc->callAlloc->_objc_rootAllocWithZone->_class_createInstanceFromZone->(instanceSize、calloc、initInstanceIsa)
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END