对于不同场景,系统提供的有不同的内存管理方案,大致有如下三种:
- TaggedPointer (对于一些小对象,比如说NSNumber等采用此种方案)
- NONPOINTER_ISA (64位架构下iOS应用程序)
- 散列表 (散列表为复杂的数据结构,包含了引用计数表和弱引用表)
NONPOINTER_ISA
arm64架构下才用
0--31位
31 | …… | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|
0 | …… | 0 | 0 | 0 | 0 | 0 |
shiftcls | shiftcls | shiftcls | shiftcls | has_cxx_dtor | has_assoc | indexed |
shiftcls | shiftcls | shiftcls | 当前对象类对象的指针地址 | 当前对象是否有使用到C++方面的内容 | 当前对象是否有关联对象 | 0:这里存的是当前对象的类对象地址;1:除地址外还有内存管理方面数据 |
63--63位
63 …… 45 | 44 | 43 | 42 | 41…… | 35…… 32 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 |
extra_rc | has_sidetable_rc | deallocting | wealy_referenced | magic | shiftcls |
储存内存管理相关 | 是否内存管理数据过大,过大或用sidetable储存 | 是否正在进行dealloc操作 | 是否有相应的弱引用指针 | magic | shiftcls |
散列表方式
SideTables()结构
SideTables()实际上是个哈希表,可通过一个对象指针,来找到它的引用计数表或者弱引用表具体在哪个sideTable中。
SideTable结构
多个sideTable,来提高效率,用分离锁来提高访问效率。
Spinlock_t 自旋锁
- Spinlock_t是“忙等”的锁
- 适用于轻量访问
RefcountMap 引用计数表
引用计数表是一个哈希表
size_t
获取真实的引用计数 需要先偏移两位