iOS 内存管理机制
2019-04-20 本文已影响0人
凛冬将至2002
iOS内存管理机制原理
iOS内存管理机制的原理是引用计数,引用计数是一个简单而有效的管理对象生命周期的方式。当这块内存被创建出来的时候,他的引用计数从0增加到1,表示有一个对象或指针持有这块内存,拥有这块内存的所有权,如果这时有另外的对象或指针指向这块内存,那么为了表示这个后来的对象或指针拥有这块内存的所有权,引用计数加1变为2,之后如果有一个对象或者指针不在指向这块内存,引用计数就减1,表示这个对象或指针不在拥有这块内存的所有权,当一块内存的引用计数变为0,表示没有任何对象或者指针持有这块内存,系统便会立即释放这块内存。
- 当我们创建一个新对象时,它的引用计数为1。
- 当有一个新的指针指向这个对象时,我们将引用计数加1。
- 当某个指针不再指向这个对象时,我们将引用计数减1。
- 当对象的引用计数为0时,说明这个对象不再被任何指针指向了,就可以将对象销毁,回收内存
ARC下的内存管理问题
1.循环引用(Reference Cycle)问题
引用计数这种管理内存的方式虽然很简单,但是有一个比较大的瑕疵,即它不能很好的解决循环引用问题。如下图所示:对象 A 和对象 B,相互引用了对方作为自己的成员变量,只有当自己销毁时,才会将成员变量的引用计数减 1。因为对象 A 的销毁依赖于对象 B 销毁,而对象 B 的销毁与依赖于对象 A 的销毁,这样就造成了我们称之为循环引用(Reference Cycle)的问题,这两个对象即使在外界已经没有任何指针能够访问到它们了,它们也无法被释放。 不止两对象存在循环引用问题,多个对象依次持有对方,形式一个环状,也可以造成循环引用问题,而且在真实编程环境中,环越大就越难被发现。下图是 4 个对象形成的循环引用问题。主动断开循环引用
解决循环引用问题主要有两个办法,第一个办法是我明确知道这里会存在循环引用,在合理的位置主动断开环中的一个引用,使得对象得以回收。如下图所示:- __weak
__weak 表示弱引用,对应定义 property 时用到的 weak。弱引用不会影响对象的释放,而当对象被释放时,所有指向它的弱引用都会自定被置为 nil,这样可以防止野指针。使用__weak修饰的变量,即是使用注册到autoreleasePool中的对象。__weak 最常见的一个作用就是用来避免循环循环。需要注意的是,__weak 修饰符只能用于 iOS5 以上的版本,在 iOS4 及更低的版本中使用 __unsafe_unretained 修饰符来代替。
__weak 的几个使用场景:
- 在 Delegate 关系中防止循环引用。
- 在 Block 中防止循环引用。
- 用来修饰指向由 Interface Builder 创建的控件。比如:@property (weak, nonatomic) IBOutlet UIButton *testButton;。
_weak弱引用的实现原理
对于__weak内存管理也借助了类似于引用计数表的散列表,它通过对象的内存地址做为key,而对应的__weak修饰符变量的地址作为value注册到weak表中,在上述代码中objc_initweak就是完成这部分操作,而objc_destroyWeak
则是销毁该对象对应的value。当指向的对象被销毁时,会通过其内存地址,去weak表中查找对应的__weak修饰符变量,将其从weak表中删除。所以,weak在修饰只是让weak表增加了记录没有引起引用计数表的变化。