Objective-C中MRC和ARC的自我理解

MRC: 手动引用计数。

 

alloc -- 分配一个对象的内存空间

retain --使一个对象的引用计数加1

release --使一个对象的引用计数减1

retainCount --获取当前对象的引用计数值

aotorelese --调用对象的aotorelease方法的话,将对象的内存管理放到aotorelease poll中,当aotorelease poll结束的时候自动调用release操作,使引用计数减1

dealloc 在MRC中调用dealloc,需要显示的调用 super dealloc方法,废弃父类的方法。

在MRC模式下必须遵循谁创建,谁释放,谁引用,谁管理

ARC : 自动引用计数

ARC是编译器(LLVM)在对应的位置自动插入retain和release操作之外,还需要Runtime的功能支持,是LLVM和Runtime协作的结果。ARC中禁止手动调用retain、release、retainCount、dealloc.

ARC中新增了weak、strong属性关键字。

MRC和ARC的区别:

1、MRC是手动管理内存,ARC是自动管理内存,由编译器和Runtime进行协作。

2、ARC中禁止调用retain、release、autorelease、retainCount、dealloc操作

在MRC下使用ARC,使用 -fobjc-arc修饰文件,启用ARC

在ARC下使用MRC,使用 -fno-objc-arc修饰文件,禁止ARC

strong和weak

strong强引用,执行了retain操作,weak弱引用,表示该属性是一种非拥有关系,没有执行retain操作。

weak属性在设置新值时既不保留新值也不会释放旧值,类似于assign;当对象被释放时,属性也会被清空。这样可以有效地防止崩溃(因为OC中给没有对象地址的指针发送消息,不会崩溃;但是给有内存地址但地址中是空对象的指针,即野指针,发送消息会崩溃)。

对于weak对象会放入一个hash表中,用weak指向的对象内存地址作为key,当此对象的引用计数值为0时会调用dealloc,使用key在hash表中搜索,将找到的所有对象置为nil。

Runtime如何实现weak变量的自动置nil?

引用计数管理

alloc的实现:

经过一些列函数的封装调用,最终调用了c函数calloc。

此时并没有设置引用计数值为1,但是我们通过retainCount获取到的引用计数值为1。这是什么原因呢?

retain的实现:

// 通过当前对象的指针,经过hash函数的运算,可以快速的在sidetables找到它对应的sidetable
SideTable& table = SideTables()[this];

// 在sidetable中去获取引用计数map这样的一个成员变量,然后通过当前对象的指针,在sidetable的引用计数表中去获取当前对象的引用计数值。
size_t& refcntStorage = table.refcnts[this];

// 对引用计数值进行加1操作,size_t 是unsign long 型的,第一位是weakly_referenced第二位是deallocating 所以这里加的值不是实际的1,而是一个宏定义 SIZE_TABLE_RC_ONE,加的一个偏移量
refcntStorage += SIDE_TABLE_RC_ONE;

// 这两次都是hash查找,也就是说在进行retain操作时经历了两次hash查找。

思考一下:我们在进行retain操作时,系统是如何查找它对应的引用计数的?

解析:通过两次hash查找,来找到它对应的引用计数值,然后进行加一操作。这里的两次查找,第一次是找到对应的sidetable表,第二次是从表的引用计数表中获取当前对象的引用计数值。

release的实现:

SideTable& table = SideTables()[this];

//根据当前对象指针访问table的引用计数表,查到它当前对应的引用计数表。
RefcountMap::iterator it = table.refcnts.find(this);

//把查找到的值进行减一操作
it ->second -= SIDE_TABLE_RC_ONE;

retainCount实现:

SideTable& table = SideTables()[this];

// 声明一个局部变量,初始值为1
size_t refcnt_result = 1;

// 通过当前对象拿到引用计数表中去查找
RefcountMap :: iterator it = table.refcnts.find(this);

// 对结果做一个向右偏移的操作,然后再结合局部变量的1进行加的操作
refcnt_result += it ->second >> SIDE_TABLE_RC_SHIFT;

这也就解释了,alloc出来的对象,我们虽然没有设置引用计数值为1,但是我们通过retainCount去获取到的引用计数值为1的原因。

dealloc的实现:

从下面流程图来讲述dealloc的实现原理:首先会先调用一个私有函数_objc_rootDealloc(),这个私有函数会调用一个rootDealloc()函数,在这个函数内部判断当前对象是否可以释放;直接释放的一个判断条件是【1、判断当前对象是否使用了非指针型isa(NONPOINTER_ISA); 2、当前对象是否有weak指针指向它,weakly_referenced; 3、当前对象是否有关联对象 has_assoc; 4、当前对象是否涉及了C++相关的代码 has_cxx_dtor以及当前对象是否使用ARC来管理内存; 5、当前对象的引用计数是否通过sidetable的引用计数表来维护的has_sidetable_rc。】如果上述5个条件有任一个满足,那就不能直接释放,需要调用object_dispose()对象清除函数。如果上述5个条件,都不满足,那就可以直接调用C函数free()直接释放。

Objective-C中MRC和ARC的自我理解

object_dispose()函数的实现

上一篇:1.13 单用户模式 1.14 救援模式 1.15 克隆虚拟机 1.16 Linux机器相互登录


下一篇:『迷你教程』掌握Xgboost损失函数构建你的完美模型