疑问???
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [p1 init];
LGPerson *p3 = [p1 init];
NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
复制代码
运行结果如下:
2021-06-07 00:46:42.553533+0800 alloc探索[26990:394582] <CJPerson: 0x6000023789d0>-0x6000023789d0-0x304e07078
2021-06-07 00:46:42.554203+0800 alloc探索[26990:394582] <CJPerson: 0x6000023789d0>-0x6000023789d0-0x304e07070
2021-06-07 00:46:42.554282+0800 alloc探索[26990:394582] <CJPerson: 0x6000023789d0>-0x6000023789d0-0x304e07068
复制代码
由此结论可知:p1,p2,p3的内存地址都是相同的,都是指向的同一块区域。那么在底层alloc和init分别都做了什么???
工欲善其事必先利其器
alloc源码初探
首先在可编译源码的main
函数入口写一个简单的代码,然后打上断点(注:这里使用的-objc4-818.2)
然后通过 Step into 进入源码
首先我们看到的是alloc
方法:
+ (id)alloc {
return _objc_rootAlloc(self);
}
复制代码
内部调用了_objc_rootAlloc()
id _objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
复制代码
进入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));
}
复制代码
经过断点调试发现调用了_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);
}
复制代码
继续进入_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;
/// 计算需要开辟的内存空间大小(内部采用了16字节对齐)
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) {
/// 关联 (将isa -> class关联起来)
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()
方法里面主要有三个核心步骤:
size = cls->instanceSize(extraBytes);
计算大小(内部采用了16字节对齐方式)obj = (id)calloc(1, size);
开辟空间obj->initInstanceIsa(cls, hasCxxDtor);
将isa和cls进行关联
总结
直接附上alloc
内部执行流程图:
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END