引用计数结构
之前我们分析过了 Swift 实例的内存结构如下:

现在我们继续分析 refCounts
InlineRefCounts
HeapObject 结构如下:
struct HeapObject {
  /// This is always a valid pointer to a metadata object.
  HeapMetadata const *metadata;
  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
#ifndef __swift__
  HeapObject() = default;
  // Initialize a HeapObject header as appropriate for a newly-allocated object.
  constexpr HeapObject(HeapMetadata const *newMetadata) 
    : metadata(newMetadata)
    , refCounts(InlineRefCounts::Initialized)
  { }
  
  // Initialize a HeapObject header for an immortal object
  constexpr HeapObject(HeapMetadata const *newMetadata,
                       InlineRefCounts::Immortal_t immortal)
  : metadata(newMetadata)
  , refCounts(InlineRefCounts::Immortal)
  { }
};
SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS 宏如下:
#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
  InlineRefCounts refCounts
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;
看到InlineRefCounts是RefCounts<InlineRefCountBits>的别名,我们点进RefCounts看下:
template <typename RefCountBits>
class RefCounts {
  std::atomic<RefCountBits> refCounts;
  // ...
}
RefCounts是一个抽象出来的模板类,所以得看传进来的InlineRefCountBits:
typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
又是一个别名,和上面操作一样,RefCountBitsT是一个模版类,但RefCountIsInline只是一个枚举,所以我们深入看下RefCountBitsT:
// RefCountIsInline: refcount stored in an object
// RefCountNotInline: refcount stored in an object's side table entry
enum RefCountInlinedness { RefCountNotInline = false, RefCountIsInline = true };
template <RefCountInlinedness refcountIsInline>
class RefCountBitsT {
  friend class RefCountBitsT<RefCountIsInline>;
  friend class RefCountBitsT<RefCountNotInline>;
  
  static const RefCountInlinedness Inlinedness = refcountIsInline;
  typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::Type
    BitsType;
  typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::SignedType
    SignedBitsType;
  typedef RefCountBitOffsets<sizeof(BitsType)>
    Offsets;
  BitsType bits;
  // ...
 }
BitsType又是RefCountBitsInt的别名,点击RefCountBitsInt的时候,我们发现有多个选项,不过 sizeof(void*)
的大小为 8,故:
// 64-bit inline
// 64-bit out of line
template <RefCountInlinedness refcountIsInline>
struct RefCountBitsInt<refcountIsInline, 8> {
  typedef uint64_t Type;
  typedef int64_t SignedType;
};
看了这么多,InlineRefCounts目前就是一个uint64_t,被RefCountBitsT操作着。
InlineRefCounts 结构
RefCountBitsT 的几个初始化函数:
  LLVM_ATTRIBUTE_ALWAYS_INLINE
  constexpr
  RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)
    : bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |
           (BitsType(unownedCount)     << Offsets::UnownedRefCountShift))
  { }
  
  LLVM_ATTRIBUTE_ALWAYS_INLINE
  constexpr
  RefCountBitsT(Immortal_t immortal)
    : bits((BitsType(2) << Offsets::StrongExtraRefCountShift) |
           (BitsType(2) << Offsets::UnownedRefCountShift) |
           (BitsType(1) << Offsets::IsImmortalShift) |
           (BitsType(1) << Offsets::UseSlowRCShift))
  { }
  LLVM_ATTRIBUTE_ALWAYS_INLINE
  RefCountBitsT(HeapObjectSideTableEntry* side)
    : bits((reinterpret_cast<BitsType>(side) >> Offsets::SideTableUnusedLowBits)
           | (BitsType(1) << Offsets::UseSlowRCShift)
           | (BitsType(1) << Offsets::SideTableMarkShift))
  {
    assert(refcountIsInline);
  }
我们点击Offsets后看到:
  typedef RefCountBitOffsets<sizeof(BitsType)>    Offsets;
  
  // 64-bit inline
// 64-bit out of line
// 32-bit out of line
template <>
struct RefCountBitOffsets<8> {
  static const size_t IsImmortalShift = 0;
  static const size_t IsImmortalBitCount = 1;
  static const uint64_t IsImmortalMask = maskForField(IsImmortal);
  static const size_t UnownedRefCountShift = shiftAfterField(IsImmortal);
  static const size_t UnownedRefCountBitCount = 31;
  static const uint64_t UnownedRefCountMask = maskForField(UnownedRefCount);
  static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
  static const size_t IsDeinitingBitCount = 1;
  static const uint64_t IsDeinitingMask = maskForField(IsDeiniting);
  static const size_t StrongExtraRefCountShift = shiftAfterField(IsDeiniting);
  static const size_t StrongExtraRefCountBitCount = 30;
  static const uint64_t StrongExtraRefCountMask = maskForField(StrongExtraRefCount);
  
  static const size_t UseSlowRCShift = shiftAfterField(StrongExtraRefCount);
  static const size_t UseSlowRCBitCount = 1;
  static const uint64_t UseSlowRCMask = maskForField(UseSlowRC);
  static const size_t SideTableShift = 0;
  static const size_t SideTableBitCount = 62;
  static const uint64_t SideTableMask = maskForField(SideTable);
  static const size_t SideTableUnusedLowBits = 3;
  static const size_t SideTableMarkShift = SideTableBitCount;
  static const size_t SideTableMarkBitCount = 1;
  static const uint64_t SideTableMarkMask = maskForField(SideTableMark);
};
这里已经能看到所有的偏移值了,我们整理成一个表格:
| 名字 | 范围(起始位置,长度 ) | 作用 | 
|---|---|---|
| PureSwiftDeallocMask | (0, 1) | 对象是否需要调用ObjC运行时来解除分配 | 
| UnownedRefCountMask | (1, 31) | 无主引用计数 | 
| IsImmortalMask | (0, 32) | 所有bit设置后,对象不会释放或具有refcount | 
| IsDeinitingMask | (32, 1) | 是否在进行反初始化 | 
| StrongExtraRefCountMask | (33, 30) | 强引用计数 | 
| UseSlowRCMask | (63, 1) | 使用慢RC | 
| SideTableMask | (0, 62) | 存放SideTable地址 | 
| SideTableUnusedLowBits | SideTable没有用到的低字节位数 | |
| SideTableMarkMask | (62, 1) | 是否存放是SideTable | 
具体结构如下:

下面的代码是 swift_retain 的过程:
static HeapObject *_swift_retain_(HeapObject *object) {
  SWIFT_RT_TRACK_INVOCATION(object, swift_retain);
  if (isValidPointerForNativeRetain(object))
    object->refCounts.increment(1);
  return object;
}
HeapObject *swift::swift_retain(HeapObject *object) {
  CALL_IMPL(swift_retain, (object));
}
// Increment the reference count.
void increment(uint32_t inc = 1) {
  auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
  RefCountBits newbits;
  do {
    newbits = oldbits;
    // 这里去增加计数
    bool fast = newbits.incrementStrongExtraRefCount(inc);
    // fast == true 引用计数没有溢出, fast == false 引用计数溢出
    if (SWIFT_UNLIKELY(!fast)) {
      if (oldbits.isImmortal())
        return;
      return incrementSlow(oldbits, inc);
    }
  } while (!refCounts.compare_exchange_weak(oldbits, newbits,
                                            std::memory_order_relaxed));
}
bool incrementStrongExtraRefCount(uint32_t inc) {
  // This deliberately overflows into the UseSlowRC field.
  bits += BitsType(inc) << Offsets::StrongExtraRefCountShift;
  return (SignedBitsType(bits) >= 0);
}
无主引用(unowned)
如下示例代码:
class Dog {
    var age = 2
    var name = "naonao"
    init() {}
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
var d = Dog()
unowned var t = d
- 无主引用和弱引用类似,不会 retain 当前实例的引用计数;
- 非可选类型,当前 t 被 unowned 修饰之后,假定永远有值,不会为空;
- 既然是非可选类型,也就意味着存在访问 Crash 的风险;
swift_unownedRetain
HeapObject *swift::swift_unownedRetain(HeapObject *object) {
  SWIFT_RT_TRACK_INVOCATION(object, swift_unownedRetain);
  if (!isValidPointerForNativeRetain(object))
    return object;
  object->refCounts.incrementUnowned(1);
  return object;
}
void incrementUnowned(uint32_t inc) {
  auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
  if (oldbits.isImmortal())
    return;
  RefCountBits newbits;
  do {
    if (oldbits.hasSideTable())
      return oldbits.getSideTable()->incrementUnowned(inc);
    newbits = oldbits;
    assert(newbits.getUnownedRefCount() != 0);
    uint32_t oldValue = newbits.incrementUnownedRefCount(inc);
    // Check overflow and use the side table on overflow.
    if (newbits.getUnownedRefCount() != oldValue + inc)
      return incrementUnownedSlow(inc);
  } while (!refCounts.compare_exchange_weak(oldbits, newbits,
                                            std::memory_order_relaxed));
}
uint32_t incrementUnownedRefCount(uint32_t inc) {
  uint32_t old = getUnownedRefCount();
  setUnownedRefCount(old + inc);
  return old;
}
弱引用
swift_weakInit
WeakReference *swift::swift_weakInit(WeakReference *ref, HeapObject *value) {
  ref->nativeInit(value);
  return ref;
}
void nativeAssign(HeapObject *newObject) {
  if (newObject) {
    assert(objectUsesNativeSwiftReferenceCounting(newObject) &&
           "weak assign native with non-native new object");
  }
  auto newSide =
    newObject ? newObject->refCounts.formWeakReference() : nullptr;
  auto newBits = WeakReferenceBits(newSide);
  auto oldBits = nativeValue.load(std::memory_order_relaxed);
  nativeValue.store(newBits, std::memory_order_relaxed);
  assert(oldBits.isNativeOrNull() &&
         "weak assign native with non-native old object");
  destroyOldNativeBits(oldBits);
}
HeapObjectSideTableEntry* RefCounts<InlineRefCountBits>::formWeakReference()
{
  auto side = allocateSideTable(true);
  if (side)
    return side->incrementWeak();
  else
    return nullptr;
}
我们可以看到,用weak的时候,会创建一张SideTable,我们详细看一下allocateSideTable的实现:
HeapObjectSideTableEntry* RefCounts<InlineRefCountBits>::allocateSideTable(bool failIfDeiniting) {
  // 获取当前的引用计数
  auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
  
  // 如果 oldbits 已经创建过 SideTable,就返回
  if (oldbits.hasSideTable()) {
    // Already have a side table. Return it.
    return oldbits.getSideTable();
  } 
  else if (failIfDeiniting && oldbits.getIsDeiniting()) {
		// 如果正在释放,do noting
    return nullptr;
  }
  // Preflight passed. Allocate a side table.
  
  // 生成 SideTable
  HeapObjectSideTableEntry *side = new HeapObjectSideTableEntry(getHeapObject());
  
  auto newbits = InlineRefCountBits(side);
  
  do {
    // 这里又做了一次判断
    if (oldbits.hasSideTable()) {
      // Already have a side table. Return it and delete ours.
      // Read before delete to streamline barriers.
      auto result = oldbits.getSideTable();
      delete side;
      return result;
    }
    else if (failIfDeiniting && oldbits.getIsDeiniting()) {
      // Already past the start of deinit. Do nothing.
      return nullptr;
    }
    
    side->initRefCounts(oldbits);
    
  } while (! refCounts.compare_exchange_weak(oldbits, newbits,
                                             std::memory_order_release,
                                             std::memory_order_relaxed));
  return side;
}
这里注意 InlineRefCountBits 的初始化参数为 :SideTable
RefCountBitsT(HeapObjectSideTableEntry* side)
  : bits((reinterpret_cast<BitsType>(side) >> Offsets::SideTableUnusedLowBits)
         | (BitsType(1) << Offsets::UseSlowRCShift)
         | (BitsType(1) << Offsets::SideTableMarkShift))
{
  assert(refcountIsInline);
}
也就是说现在的 refConts 变成了如下:

继续看 incrementWeak 函数:
void incrementWeak() {
  auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
  RefCountBits newbits;
  do {
    newbits = oldbits;
    assert(newbits.getWeakRefCount() != 0);
    newbits.incrementWeakRefCount();
    if (newbits.getWeakRefCount() < oldbits.getWeakRefCount())
      swift_abortWeakRetainOverflow();
  } while (!refCounts.compare_exchange_weak(oldbits, newbits,
                                            std::memory_order_relaxed));
}
这样,我们整个weak的操作流程已经完成了,我们总结下
当使用弱引用的时候,我们会查看当前对象的SideTable是否已经创建了,如果创建了,SideTable中弱引用计数加一,如果没有创建,那么先创建,把当前对象的引用计数存在SideTable中,在把弱引用计数加一。操作完后,我们把SideTable处理过的地址赋给当前对象的引用计数。
换句话说,一旦我们使用了weak修饰词,那么对象引用计数的内存里存放的不在是强引用和无主引用的个数,而是对应SideTable的地址,真正的强引用和无主引用的个数存在了SideTable中。
HeapObjectSideTableEntry
我们刚才从代码可以看到SideTable用的是HeapObjectSideTableEntry,这样可以看下SideTable的大概结构
class HeapObjectSideTableEntry {
  // FIXME: does object need to be atomic?
  std::atomic<HeapObject*> object;
  SideTableRefCounts refCounts;
  ...
}
我们可以看到里面有个HeapObject的指针,然后还有个SideTableRefCounts,我们点击SideTableRefCounts,又会来到这边:
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;
这次我们看的是SideTableRefCountBits:
class alignas(sizeof(void*) * 2) SideTableRefCountBits : public RefCountBitsT<RefCountNotInline>
{
  uint32_t weakBits;
  ...
}
SideTableRefCountBits继承与RefCountBitsT,所以也会有一个bits属性,存放的就是对应对象的强引用和无主引用的个数,这个weakBits存放的就是弱引用的个数,我们等会到项目里验证一下。
验证
如下示例:
class Dog {
    var age = 2
    var name = "naonao"
    init() {}
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
var d = Dog()
weak var a = d
weak var b = d
weak var c = d
var e = d
print(d)
整个变化如下:

循环引用
如下示例代码,会发生循环引用:
class Dog {
    var age = 2
    var name = "naonao"
    var complete: (() -> ())?
    deinit {
        print("Dog release ...")
    }
}
func test() {
    let d = Dog()
    d.complete = {
        d.age += 1
    }
}
test()
如何解决呢,两种方法:
- unowned
let d = Dog()
d.complete = { [unowned d] in
    d.age += 1
}
- weak
let d = Dog()
d.complete = { [weak d] in
    d?.age += 1
}
捕获列表
如下示例代码的大括号就是捕获列表的语法:
d.complete = { [weak d] in
    d?.age += 1
}
如下示例代码:
let d = Dog()
var height = 0
var width  = 0
d.complete = { [weak d, height] in
    d?.age += 1
    print("height: \(height) width: \(width)")
}
width = 10
height = 5
d.complete?()
// height: 0 width: 10
你会发现 block 中的 height 的值并没有变化,很像一个 block 内部的常量,不可被改变,而 width 可以被外界影响,这是捕获列表的特性。