自动引用计数(ARC,Automatic Reference Counting),是指内存中对引用采取自动计数的技术。在LLVM编译器中设置ARC为有效状态,就无需再次键入retain或release代码。
本文为《Objective-C高级编程》第一章读书笔记
内存管理的思考方式
- 主要思路:
- 自己生成的对象,自己持有
- 非自己生成的对象,自己也能持有
- 不再需要自己持有的对象被释放
- 非自己持有的对象无法释放
- OC中对象操作的方法有:
对象操作 | OC方法 |
---|---|
生成并持有对象 | alloc/new/mutableCopy等 |
持有对象 | retain |
释放对象 | release |
废弃对象 | dealloc |
alloc/retain/release/dealloc实现
由于Foundation框架并没有开源,所以实现部分用的是GNUstep框架源码。两者的行为和方式是一样的,所以理解了GNUstep源代码就相当于理解了苹果的cocoa实现。
alloc
- 下面列出执行
alloc
方法所调用的方法和函数:
1 |
+ alloc |
retainCount/retain/release
1 |
// 上面方法名,下面底层调用 |
可以看到上面的代码都调用了同一个函数__CFDoExternRefOperation
,该函数源码:
1 |
int __CFDoExternRefOperation(uintptr_t op, id obj) { |
从以上的代码可以看出,苹果的实现大概是采用哈希表(引用计数表)来管理引用计数,这样做的好处在于引用计数表各记录中存有内存块地址,可以从各个记录中追溯到各个对象的内存块。它的意义在于调试的时候,即使出现故障导致对象占用的内存块损坏,但只要引用计数表还在,就能确认各内存块的位置,在利用工具检测内存泄漏时,引用计数表的各记录也有助于检测各对象持有者是否存在。
autorelease
autorelease
类似于C语言中自动变量的特性,C语言中程序执行时,若某自动变量超出其作用域,该自动变量将被自动废弃。
autorelease
的具体使用方法如下:
- 生成并持有NSAutoreleasePool对象
- 调用分配对象的autorelease实例方法
- 废弃NSAutoreleasePool对象
autorelease实现
关键类:AutoreleasePoolPage
1 |
class AutoreleasePoolPage |
所有权修饰符
ARC有效时,类型必须附加所有权修饰符,所有权修饰符一共有4种:
__strong
__weak
__unsafe_unretained
__autoreleasing
__strong修饰符
附有
__strong
修饰符的变量在超出其作用域时,即在该变量被废弃时,会释放其被赋予的对象
__weak修饰符
仅通过
__strong
修饰符不能解决某些重大问题—-引用计数式内存管理中的循环引用问题
如以下源码所示:
1 |
@interface : NSObject |
所谓内存泄漏就是应当废弃的对象在超出其生存周期后继续存在。对象持有自身时也会发生循环引用
避免循环可以使用__weak
修饰符,在超出其变量作用域时,对象即被释放。__weak
修饰符还有一个优点,就是若该变量被废弃,则此弱引用将自动失效并且处于nil被赋值的状态。
1 |
id __weak obj1 = nil; |
__unsafe_unretained修饰符
__unsafe_unretained
修饰符是不安全的所有权修饰符。附有该修饰符的变量不属于编译器内存管理的对象
附有__unsafe_unretained
修饰符的变量同附有__weak
修饰符的变量相同的是,自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放。不同之处看下面的代码和注释
1 |
id __unsafe_unretained obj1 = nil |
最后一行的NSLog只是碰巧正常运行而已,虽然访问已经废弃的对象但应用程序在个别运行情况下才会崩溃。在使用__unsafe_unretained
时,赋值给__strong
修饰符的变量时有必要确保被赋值对象确实存在。这个修饰符的存在意义在于iOS4以前的应用必须使用__unsafe_unretained
替代__weak
。
__autoreleasing修饰符
ARC有效时,不能使用autorelease方法,也不能用NSAutoreleasePool类。虽然autorelease无法直接使用,但实际上,ARC有效时autorelease功能是起作用的。
1 |
// ARC无效时 |
ARC有效时,要通过将对象赋值给附加了__autoreleasing
修饰符的变量来替代调用autorelease方法。总的来说,就是ARC有效时,用@autoreleasepool
块替代NSAutoreleasePool
类,用附有__autoreleasing
修饰符替代autorelease
方法。
但为什么很少见到显式地调用上面所述的标识符呢?因为编译器会检查方法名是否以alloc/new/copy/mutableCopy
开始,如果不是,则将返回值的对象注册到autoreleasepool
。
实际上,访问附有__weak
修饰符的变量必须访问注册到autoreleasepool
的对象。因为访问弱引用持有的对象时,该对象有可能被废弃掉,所以把它注册到autoreleasepool
中,在自动释放池结束之前都能确保对象存在。
属性
属性声明的属性 | 所有权修饰符 |
---|---|
assign | __unsafe_unretained修饰符 |
copy | __strong修饰符(赋值的是被复制的对象) |
retain | __strong修饰符 |
strong | __strong修饰符 |
weak | __weak修饰符 |
__unsafe_unretained | __unsafe_unretained修饰符 |
近期评论