OC内存管理--对象的生成与销毁
栏目: Objective-C · 发布时间: 5年前
内容简介:原文链接在iOS开发中了,我们每天都会使用整个过程其实就是
原文链接 OC内存管理--对象的生成与销毁
在iOS开发中了,我们每天都会使用 + alloc
和 - init
这两个方进行对象的初始化。我们也这知道整个对象的初始化过程其实就是 开辟一块内存空间,并且初始化isa_t结构体的过程 。
alloc的实现
+ (id)alloc { return _objc_rootAlloc(self); } id _objc_rootAlloc(Class cls) { return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/); } 复制代码
整个过程其实就是 NSObject
对 callAlloc
方法的实现。
callAlloc
/* cls:CustomClass checkNil:是否检查Cls allocWithZone:是否分配到指定空间,默认为false,内部会对其进行优化 */ static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) { //没有class或则checkNil为YES,返回空 if (slowpath(checkNil && !cls)) return nil; //确保只有Objective-C 2.0语言的文件所引用 #if __OBJC2__ //判断class有没有默认的allocWithZone方法 if (fastpath(!cls->ISA()->hasCustomAWZ())) { // class可以快速分配 if (fastpath(cls->canAllocFast())) { //hasCxxDtor();是C++析构函数,判断是否有析构函数 bool dtor = cls->hasCxxDtor(); //申请class的内存空间 id obj = (id)calloc(1, cls->bits.fastInstanceSize()); if (slowpath(!obj)) return callBadAllocHandler(cls); //初始化isa指针 obj->initInstanceIsa(cls, dtor); return obj; } else { //使用class_createInstance创建class id obj = class_createInstance(cls, 0); if (slowpath(!obj)) return callBadAllocHandler(cls); return obj; } } #endif //说明有默认的allocWithZone的方法,调用allocWithZone方法 if (allocWithZone) return [cls allocWithZone:nil]; return [cls alloc]; } 复制代码
在 __OBJC2__
下当前类有没有默认的 allocWithZone
方法是通过 hasCustomAWZ()
函数判断的。 YES
代表有则会调用 [cls allocWithZone:nil]
方法。 NO
代表没有,这时候会根据当前类是否可以快速分配, NO
的话调用 class_createInstance
函数; YES
则分配内存并初始化isa。
allocWithZone
+ (id)allocWithZone:(struct _NSZone *)zone { return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone); } id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone) { id obj; #if __OBJC2__ // allocWithZone under __OBJC2__ ignores the zone parameter (void)zone; obj = class_createInstance(cls, 0); #else if (!zone) { obj = class_createInstance(cls, 0); } else { obj = class_createInstanceFromZone(cls, 0, zone); } #endif if (slowpath(!obj)) obj = callBadAllocHandler(cls); return obj; } 复制代码
allocWithZone
函数的本质是调用 _objc_rootAllocWithZone
函数。
_objc_rootAllocWithZone
的逻辑分为两种情况:
- 先判断是否是
__OBJC2__
,如果是则调用class_createInstance
; - 判断
zone
是否为空,如果为空调用class_createInstance
,如果不为空,调用class_createInstanceFromZone
。
//class_createInstance id class_createInstance(Class cls, size_t extraBytes) { return _class_createInstanceFromZone(cls, extraBytes, nil); } //class_createInstanceFromZone id class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone) { return _class_createInstanceFromZone(cls, extraBytes, zone); } 复制代码
class_createInstance
和 class_createInstanceFromZone
的本质都是调用 _class_createInstanceFromZone
。
另外通过前面的源代码我们可以发现: 用alloc方式创建,只要当前类有allocWithZone方法,最终一定是调用class_createInstance 。
_class_createInstanceFromZone
static __attribute__((always_inline)) id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, bool cxxConstruct = true, size_t *outAllocatedSize = nil) { if (!cls) return nil; assert(cls->isRealized()); bool hasCxxCtor = cls->hasCxxCtor();//构造函数 bool hasCxxDtor = cls->hasCxxDtor();//析构函数 bool fast = cls->canAllocNonpointer(); //是对isa的类型的区分,如果一个类不能使用isa_t类型的isa的话,fast就为false,但是在Objective-C 2.0中,大部分类都是支持的 //在分配内存之前,需要知道对象在内存中的大小,也就是instanceSize的作用。对象必须大于等于16字节。 size_t size = cls->instanceSize(extraBytes); if (outAllocatedSize) *outAllocatedSize = size; id obj; if (!zone && fast) { //分配内存空间 obj = (id)calloc(1, size); if (!obj) return nil; //初始化isa指针 obj->initInstanceIsa(cls, hasCxxDtor); } else { //此时的fast 为 false //在 C语言 中,malloc表示在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址;calloc表示在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。 if (zone) { obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size); } else { obj = (id)calloc(1, size); } if (!obj) return nil; //初始化isa指针 obj->initIsa(cls); } if (cxxConstruct && hasCxxCtor) { obj = _objc_constructOrFree(obj, cls); } return obj; } 复制代码
初始化isa
_class_createInstanceFromZone
中不光开辟了内存空间,还初始化了isa。初始化isa的方法有 initInstanceIsa
和 initIsa
,但是本质都是调用 initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
。
inline void objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) { assert(!isTaggedPointer()); if (!nonpointer) { isa.cls = cls; //obj->initIsa(cls) } else { //obj->initInstanceIsa(cls, hasCxxDtor); assert(!DisableNonpointerIsa); assert(!cls->instancesRequireRawIsa()); isa_t newisa(0); #if SUPPORT_INDEXED_ISA assert(cls->classArrayIndex() > 0); newisa.bits = ISA_INDEX_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #else newisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.shiftcls = (uintptr_t)cls >> 3; #endif // This write must be performed in a single store in some cases // (for example when realizing a class because other threads // may simultaneously try to use the class). // fixme use atomics here to guarantee single-store and to // guarantee memory order w.r.t. the class index table // ...but not too atomic because we don't want to hurt instantiation isa = newisa; } } 复制代码
根据《OC引用计数器的原理》,现在再看一下初始化isa的方法。这个方法的意思是首先判断是否开启指针优化。
没有开启指针优化的话访问 objc_object
的 isa
会直接返回 isa_t
结构中的 cls
变量, cls
变量会指向对象所属的类的结构。
开启指针优化的话通过 newisa(0)
函数初始化一个isa,并根据 SUPPORT_INDEXED_ISA
分别设置对应的值。iOS设备的话这个值是0,所以执行 else
的代码。
到这里alloc的实现过程已经结束了,根据上面的源码分析,用一张图表示上述过程:
这里可能会有个疑问,既然 alloc
将分配内存空间和初始化isa的事情都做了,那么 init
的作用是什么呢?
init
- (id)init { return _objc_rootInit(self); } id _objc_rootInit(id obj) { return obj; } 复制代码
init
的作用就是返回当前对象。这里有个问题既然 init
只是返回当前对象,为什么要多此一举呢?
Apple给出的注释:
In practice, it will be hard to rely on this function. Many classes do not properly chain -init calls.
意思是在实践中,很难依靠这个功能。许多类没有正确链接 init
调用。所以这个函数很可能不被调用。也许是历史遗留问题吧。
new
+ (id)new { return [callAlloc(self, false/*checkNil*/) init]; } 复制代码
所以说 UIView *view = [UIView new];
和 UIView *view = [[UIView alloc]init];
是一样的。
dealloc
分析了对象的生成,我们现在看一下对象是如何被销毁的。 dealloc
的实现如下:
- (void)dealloc { _objc_rootDealloc(self); } void _objc_rootDealloc(id obj) { assert(obj); obj->rootDealloc(); } inline void objc_object::rootDealloc() { if (isTaggedPointer()) return; // fixme necessary? if (fastpath(isa.nonpointer && !isa.weakly_referenced && !isa.has_assoc && !isa.has_cxx_dtor && !isa.has_sidetable_rc)) { assert(!sidetable_present()); free(this); } else { object_dispose((id)this); } } 复制代码
rootDealloc
分为三种情况:
object_dispose
objc_destructInstance
我们先看 object_dispose
函数的源码:
id object_dispose(id obj) { if (!obj) return nil; objc_destructInstance(obj); free(obj); return nil; } 复制代码
做了两件事情:
objc_destructInstance
objc_destructInstance
的实现如下:
/*********************************************************************** * objc_destructInstance * Destroys an instance without freeing memory. * Calls C++ destructors. * Calls ARC ivar cleanup. * Removes associative references. * Returns `obj`. Does nothing if `obj` is nil. **********************************************************************/ void *objc_destructInstance(id obj) { if (obj) { // Read all of the flags at once for performance. bool cxx = obj->hasCxxDtor();//是否有析构函数 bool assoc = obj->hasAssociatedObjects();//是否有关联对象 // This order is important. if (cxx) object_cxxDestruct(obj);//调用析构函数 if (assoc) _object_remove_assocations(obj);//删除关联对象 obj->clearDeallocating();//清空引用计数表并清除弱引用表 } return obj; } 复制代码
objc_destructInstance
做了三件事情:
object_cxxDestruct _object_remove_assocations clearDeallocating
object_cxxDestruct
在源码中 object_cxxDestruct
的实现由 object_cxxDestructFromClass
完成。
static void object_cxxDestructFromClass(id obj, Class cls) { void (*dtor)(id); // Call cls's dtor first, then superclasses's dtors. for ( ; cls; cls = cls->superclass) { if (!cls->hasCxxDtor()) return; dtor = (void(*)(id)) lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct); if (dtor != (void(*)(id))_objc_msgForward_impcache) { if (PrintCxxCtors) { _objc_inform("CXX: calling C++ destructors for class %s", cls->nameForLogging()); } (*dtor)(obj); } } } 复制代码
这段代码的意思就是沿着继承链逐层向上搜寻 SEL_cxx_destruct
这个 selector
,找到函数实现(void (*)(id)(函数指针)并执行。说白了就是找析构函数,并执行析构函数。
析构函数中书如何处理成员变量的?
objc_storeStrong(&ivar, nil) objc_destroyWeak(&ivar)
关于这个函数 Sunnyxx ARC下dealloc过程及.cxx_destruct的探究 中也有提到。
用一张图表示 dealloc
的流程:
至于 dealloc
的调用时机,是跟引用计数器相关的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 销毁servlet
- Python:线程之定位与销毁
- 浅谈TCP连接的创建和销毁过程
- 《Effective Java》学习笔记(一)——创建和销毁对象
- Android可见APP的不可见任务栈(TaskRecord)销毁分析
- android – 如何告诉我的自定义FragmentPagerAdapter来停止销毁我的碎片?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Orange'S:一个操作系统的实现
于渊 / 电子工业出版社 / 2009-6 / 69.00元
《Orange S:一个操作系统的实现》从只有二十行的引导扇区代码出发,一步一步地向读者呈现一个操作系统框架的完成过程。书中不仅关注代码本身,同时关注完成这些代码的思路和过程。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。读者可以根据路线图逐步完成各部分的功能,从而避免了一开始就面对整个操作系统数万行代码时的迷茫和挫败感。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不......一起来看看 《Orange'S:一个操作系统的实现》 这本书的介绍吧!