03-主题|内存管理@iOS-引用计数与MRC详解

5 阅读3分钟

本文介绍 引用计数(Reference Counting) 的原理、MRC(Manual Reference Counting,手动引用计数) 下的规则与配对原则,以及 retain/release/autorelease 的语义与典型用法。ARC 在此基础上由编译器自动插入,见 04-ARC详解


MRC 是什么(简要介绍)

MRCManual Reference Counting:由开发者手动调用 retainreleaseautorelease 来增加或减少对象的引用计数,从而决定对象何时被释放。在 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详解


参考文献