本文介绍: MRC: 手动引用计数alloc — 分配一个对象内存空间retain –使一个对象的引用计数加1release –使一个对象的引用计数减1retainCount获取当前对象的引用计数aotorelese —调用对象aotorelease方法的话,将对象内存管理放到aotorelease poll中,当aotorelease poll结束的时候自动调用release操作,使引用计数减1dealloc 在MRC中调用dealloc需要显示的调用 super d

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中新增了weakstrong属性关键字。

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使用keyhash表中搜索,将找到的所有对象置为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()函数的实现

原文地址:https://blog.csdn.net/A_Mona/article/details/114384360

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_10169.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注