简单聊聊类在创建对象,即 alloc init时底层到底做了什么?
我们知道所有的类都继承于NSObject,alloc init也是其自带的类方法,所以就从NSObject下手
此时找到源码看看:源码地址,此时版本是objc4-818.2
alloc方法做了什么?
先找到NSObject.mm文件看看alloc调用流程
+ (id)alloc {
return _objc_rootAlloc(self);
}
进入_objc_rootAlloc
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
再进入callAlloc方法
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
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));
}
补充一下:
slowpath 、fastpath是告诉编译器,if中的条件是大概率(fastpath)还是小概率(slowpath)事件,从而编译器进行优化;
条件判断if __OBJC2__是根据OC版本进入不同条件,当前OC版本就是2.X
从上面callAlloc方法可以看出:
if (slowpath(checkNil && !cls)) return nil;基本上不会执行;
cls->ISA()->hasCustomAWZ()是判断该类是否实现了allocWithZone方法,否,会调用_objc_rootAllocWithZone
关于hasCustomAWX() AWZ = allocWithZone 这里表示有没有alloc / allocWithZone的实现
下面进入_objc_rootAllocWithZone方法 (该方法在objc-runtime-new.mm文件里)
NEVER_INLINE
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方法,这个方法实现了内存的分配及把isa关联到相应的类
/***********************************************************************
* class_createInstance //创建实例
* fixme
* Locking: none
*
* Note: this function has been carefully written so that the fastpath
* takes no branch. //这个函数经过了细致的编写,因此fastpath不需要进行分支。
**********************************************************************/
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());//断言,isRealized是防止并发,保持运行时锁。
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();//判断当前class或者superclass是否有.cxx_construct 构造方法的实现
bool hasCxxDtor = cls->hasCxxDtor();//判断判断当前class或者superclass是否有.cxx_destruct 析构方法的实现
bool fast = cls->canAllocNonpointer();//具体标记某个类是否支持优化的isa
size_t size; // 声明内存空间大小
size = cls->instanceSize(extraBytes); //计算需要的内存大小,考虑到16字节内存对齐,下面会讲到这个方法
if (outAllocatedSize) *outAllocatedSize = size; //outAllocatedSize没传,默认为nil
//向系统申请开启内存,返回地址指针
id obj;
if (zone) { //当前zone传过来的是nil
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
// alloc 开辟内存的地方
// 向系统申请size大小的空间,并且calloc()函数会默认的把申请出来的空间初始化为0或者nil,并返回一个指向它的指针
//补充一下,callo与malloc都是申请内存,但malloc 不会设置内存为0
obj = (id)calloc(1, size);
}
// 判断是否分配成功,如果分配不成功就返回nil,但用了slowpath就说明概率很低
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
//关联到相应的类
if (!zone && fast) {
obj->initInstanceIsa(cls, hasCxxDtor); //初始化实例的isa指针与cls类对象关联
} 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方法可以看出:
一进来就进行断言,防止并发;之后判断是否有构造方法、析构方法的实现等(C++内容);之后先计算需要的内存,再去申请内存空间;最后将开辟的内存地与类对象做关联。
计算需要内存空间大小instanceSize()
inline 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;
}
可以看出系统至少分配16个字节,即使小于16也会返回16
init 方法
// Replaced by CF (throws an NSException)
+ (id)init {
return (id)self;
}
- (id)init {
return _objc_rootInit(self);
}
id
_objc_rootInit(id obj)
{
// In practice, it will be hard to rely on this function.
// Many classes do not properly chain -init calls.
return obj;
}
基本上都是直接返回了obj 没有做其他操作
还有一种创建对象的方法,就是new
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
相当于 alloc 方法 加上 init 方法
总结alloc底层调用过程
1、类调用了
alloc方法后,底层会调用_objc_rootAlloc方法,再调用callAlloc方法;2、在
callAlloc方法中,判断是否分配过空间,没有就会调用_objc_rootAllocWithZone;3、在
_objc_rootAllocWithZone中调用_class_createInstanceFromZone方法;4、> 在
_class_createInstanceFromZone方法中,先计算出需要的内存空间(为了保持内存对齐,系统会分配16个字节),再向系统申请空间,申请成功后系统会返回该空间地址的指针(isa),最后将地址与cls类对象做关联。
以上若有错误,欢迎指正。转载请注明出处。