Day12-ARC 本质、Weak 实现、循环引用处理
一、ARC 的本质(Automatic Reference Counting)
ARC 是编译器级别的内存管理机制,由 Clang 编译器在编译时插入 retain/release/autorelease 相关的代码。
核心机制
- 每个对象都有一个 引用计数(retain count)。
- 强引用(strong)+1(retain),释放 -1(release)。
- 引用计数为 0 时,调用
dealloc
释放对象。
- ARC 只管理对象内存,不管理 malloc/free 的非对象内存。
二、Weak 的实现原理
__weak
不增加引用计数,用于避免循环引用,自动在对象销毁时置为 nil
。
weak_table_t 全局结构
- 存储所有 weak 引用对象与对应指针地址。
- 每个对象记录在一个
weak_entry_t
中:
1 2 3 4
| struct weak_entry_t { DisguisedPtr<objc_object> referent; weak_referrer_t *referrers; };
|
objc_storeWeak(id *location, id obj)
- 清除旧值
- 设置新值,并注册到
weak_table_t
对象销毁时:
- 调用
objc_clearWeakRefs
,将所有 weak 指针置 nil
三、循环引用及处理方式
循环引用定义
- 当两个对象互相强引用,引用计数永远不为 0,导致内存泄漏。
解决方法
- 使用
__weak
或 __unsafe_unretained
- 在 block 中使用
[weak self]
或 [unowned self]
- delegate 常使用
weak
四、底层实现:引用计数存储与操作
isa_t 结构(64 位系统)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| union isa_t { uintptr_t bits; struct { uintptr_t nonpointer : 1; uintptr_t has_assoc : 1; uintptr_t has_cxx_dtor : 1; uintptr_t shiftcls : 44; uintptr_t magic : 6; uintptr_t weakly_referenced : 1; uintptr_t deallocating : 1; uintptr_t has_sidetable_rc : 1; uintptr_t extra_rc : 8; }; };
|
- 引用计数快速路径,最大 255。
- 超过后,引用计数信息存入 SideTable。
SideTable 结构
1 2 3 4 5
| struct SideTable { spinlock_t slock; RefcountMap refcnts; weak_table_t weak_table; };
|
五、objc_retain 和 objc_release 底层逻辑
objc_retain(id obj)
1 2 3 4 5
| id objc_retain(id obj) { if (obj == nil) return nil; if (obj->isa.tryRetain()) return obj; return retainSlow(obj); }
|
objc_release(id obj)
1 2 3 4 5
| void objc_release(id obj) { if (obj == nil) return; if (obj->isa.tryRelease()) return; releaseSlow(obj); }
|
六、__weak 与 __unsafe_unretained 对比
特性 |
__weak |
__unsafe_unretained |
是否增加引用计数 |
否 |
否 |
对象释放后指针 |
自动 nil |
悬垂指针 |
安全性 |
高 |
低 |
性能 |
稍低 |
高 |
七、调试与优化建议
调试工具
[object retainCount]
po [obj retainCount]
(LLDB)
- 设置环境变量:
1
| export OBJC_PRINT_RETAIN_RELEASE=YES
|
优化建议
- weak 有性能开销,频繁使用需谨慎。
- block 捕获 self 时建议使用
[weak self]
。
八、总结架构图示(文字版)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ┌──────────────┐ │ ARC 编译器插入 │ └──────┬───────┘ ↓ ┌─────────────┐ │ isa_t 的 extra_rc │ <───<255 快路径 └──────┬──────┘ ↓ ┌──────────────┐ │ SideTable 存储引用计数 │ └──────┬───────┘ ↓ ┌─────────────┐ │ weak_table_t │ ← weak引用管理 └─────────────┘
|