本文介绍 引用计数(Reference Counting) 的原理、MRC(Manual Reference Counting,手动引用计数) 下的规则与配对原则,以及 retain/release/autorelease 的语义与典型用法。ARC 在此基础上由编译器自动插入,见 04-ARC详解。
MRC 是什么(简要介绍)
MRC 即 Manual Reference Counting:由开发者手动调用 retain、release、autorelease 来增加或减少对象的引用计数,从而决定对象何时被释放。在 iOS 5 之前是 Objective-C 的主流方式;理解 MRC 的规则与配对原则,是理解 ARC 和自动释放池的基础。下文的「引用计数原理」与「加一/减一规则」同时适用于 MRC 与 ARC,ARC 只是把这些调用交给编译器自动插入。
一、引用计数原理
1.1 基本思想
- 每个堆上对象维护一个引用计数(retain count):表示当前有多少处「引用」正在使用该对象。
- 引用计数为 0 时,对象不再被任何引用使用,系统销毁对象并回收内存。
- +1:新增加一处引用(如持有、拷贝得到新指针);-1:减少一处引用(如不再持有、释放)。
1.2 规则小结
| 事件 | 引用计数变化 |
|---|---|
| 创建对象(alloc/new/copy/mutableCopy) | +1,创建者持有 |
| retain | +1 |
| release | -1 |
| autorelease | 将「稍后 -1」交给当前 AutoreleasePool 处理 |
1.3 流程图:对象生命周期
flowchart LR
A[alloc/new 等] --> B[rc=1]
B --> C{有 retain?}
C -->|是| D[rc+=1]
D --> C
C -->|否| E{有 release/autorelease?}
E -->|是| F[rc-=1]
F --> G{rc==0?}
G -->|是| H[dealloc 回收]
G -->|否| E
二、MRC 下的「加一」与「减一」
2.1 引用计数 +1 的操作
| 方法/操作 | 说明 |
|---|---|
| alloc | 分配内存并返回对象,调用者拥有,rc 初始为 1 |
| new | 等价于 alloc + init,调用者拥有 |
| copy / mutableCopy | 得到新对象,调用者拥有新对象(rc=1) |
| retain | 对已有对象调用,表示多一处引用,rc+1 |
2.2 引用计数 -1 的操作
| 方法/操作 | 说明 |
|---|---|
| release | 立即减少引用计数,rc-1;若 rc 变为 0 则 dealloc |
| autorelease | 将对象加入当前 AutoreleasePool,在池 drain 时对该对象 release(延迟 -1) |
2.3 配对原则(MRC 核心)
- 谁让引用计数 +1,谁就要在合适时机让引用计数 -1(自己 release 或 autorelease)。
- 若只 +1 不 -1 → 泄漏;若多 -1 或对已释放对象再访问 → 野指针/崩溃。
三、伪代码与算法说明
3.1 retain / release 语义(伪代码)
函数 retain(obj):
若 obj == nil: 返回 nil
obj.retainCount += 1
返回 obj
函数 release(obj):
若 obj == nil: 返回
obj.retainCount -= 1
若 obj.retainCount == 0:
调用 obj.dealloc
释放对象内存
3.2 autorelease 语义(伪代码)
函数 autorelease(obj):
若 obj == nil: 返回 nil
将 obj 加入当前线程的 AutoreleasePool 栈顶
返回 obj
// 当 AutoreleasePool pop/drain 时,对池内每个对象调用 release
3.3 MRC 下典型写法示例(Objective-C)
// 创建并持有:alloc 后 rc=1,需要在不使用时 release
NSObject *obj = [[NSObject alloc] init];
// ... 使用 obj ...
[obj release];
// 通过方法返回「已 autorelease」的对象:调用者不拥有,不需 release
- (NSString *)name {
return [[[NSString alloc] initWithFormat:@"name"] autorelease];
}
四、所有权与命名约定(MRC 时代)
- 方法名以 alloc / new / copy / mutableCopy 开头:返回的对象调用者拥有,需负责 release 或 autorelease。
- 其他返回对象的方法:默认约定返回 autorelease 对象,调用者不拥有,不应 release(除非先 retain)。
五、与 ARC 的衔接
ARC 仍基于同一套引用计数规则,只是 retain/release/autorelease 由编译器在编译期自动插入;开发者通过 strong/weak 等修饰符表达所有权,编译器据此生成对应的 retain/release。详见 04-ARC详解。