源码解析

ARC中的数据结构以及寻址方式

2018-10-15  本文已影响46人  哦呵呵y

iOS ARC中引用计数的实现
iOS weak 的实现
ARC中的数据结构以及寻址方式

一 、 isa中使用了联合体,通过结构体位段的方式存储,
二 、 SideTables

SideTables 是一个长度为64的hash表,以对象地址进行hash算法获取存储位置,内部存储类型为SideTable结构体,这里使用了分离锁,对每个SideTable对象单独加锁,降低锁的竞争程度。

三 、 SideTable---->RefcountMap
  1. SideTable中RefcountMap存储了对象额外的引用计数,RefcountMap内部包含一个c++迭代器,利用std::pair<KeyT, ValueT>,将对象作为Key,引用计数信息作为Value打包存储,
  2. 其中Value为size_t类型
#define SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)
#define SIDE_TABLE_DEALLOCATING      (1UL<<1)  // MSB-ward of weak bit
#define SIDE_TABLE_RC_ONE            (1UL<<2)  // MSB-ward of deallocating bit
#define SIDE_TABLE_RC_PINNED         (1UL<<(WORD_BITS-1))

#define SIDE_TABLE_RC_SHIFT 2
#define SIDE_TABLE_FLAG_MASK (SIDE_TABLE_RC_ONE-1)
四 、 SideTable---->weak_table_t
struct weak_table_t {
    weak_entry_t *weak_entries;     弱引用表
    size_t    num_entries;                 当前使用总数量
    uintptr_t mask;                            
    uintptr_t max_hash_displacement;
};
  1. weak_table_t 中存储了弱引用表,weak_entries默认存储空间为64,当存储内容num_entries大于总容量的 3 / 4时 空间扩大一倍。
  2. 既然是hash表,就要有hash算法来决定存储位置。一般来说会取hash值对数组容量模运算获取要存储的位置,而这里使用了 mask
    hash_pointer(new_entry->referent) & (weak_table->mask);
    mask = 总容量 - 1 而且每次扩张会进行翻倍
    64 0100 0000 63 0011 1111
    128 1000 0000 127 0111 1111
    利用mask与hash值按位与操作,0的位永远为0,1的为返回hash值本身,所以最大值为总容量-1,最小值为0,从而获取要存储的位置。
  3. hash表使用了开放寻址法处理冲突,如果有冲突,则依次往下偏移,直到没有冲突位置,并且max_hash_displacement保存最大偏移,
    即比如在插入过程中有5次碰撞,那max_hash_displacement=5,如果下次插入新对象有10次碰撞,max_hash_displacement=10;作用就是在下次查找entry,根据计算得到的索引相继累加查找对象,如果累加次数大于max_hash_displacement就不继续检索了,直接返回nil;避免遍历整个数组去找对象,浪费性能;
  4. weak_entry_t保存了一个对象所关联的所有弱引用对象,如果长度超过4,则使用一个hash表,并且查找方式类似于上面
上一篇下一篇

猜你喜欢

热点阅读