ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-02-28 19:04:54  阅读:229  来源: 互联网

标签:调用 对象 计数 ARC 引用 Objective retain MRC


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有