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()直接释放。
object_dispose()函数的实现
标签:调用,对象,计数,ARC,引用,Objective,retain,MRC 来源: https://blog.csdn.net/A_Mona/article/details/114384360