Day12-ARC 本质、Weak 实现、循环引用处理

YVTU

一、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)

  1. 清除旧值
  2. 设置新值,并注册到 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;
};
};

extra_rc

  • 引用计数快速路径,最大 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引用管理
└─────────────┘