引用计数简单学习

本文介绍了Swift中引用计数的实现,重点关注InlineRefCounts和SideTableRefCounts。RefCounts模板类持有atomic<RefCountBits>,其中RefCountBits根据平台位宽分为32位和64位。在64位系统中,BitsType是一个无符号64位整型,作为引用计数的核心。当涉及弱引用时,会调用一系列方法如nativeInit、formWeakReference及allocateSideTable,其中HeapObjectSideTableEntry包含指向对象的指针和SideTableRefCounts类型的引用计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

InlineRefCounts refcounts

typedef RefCounts<InlineRefCountBits> InlineRefCounts;
typedef RefCounts<SideTableRefCountBits> SideTableRefCounts;

RefCounts是一个模版类,主要看尖括号里的东西。

class RefCounts { std::atomic<RefCountBits> refCounts; .... }

然后看RefCountBits是啥

typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
又是一个别名,和上面操作一样,RefCountBitsT是一个模版类,但RefCountIsInline只是一个枚举,所以我们深入看下RefCountBitsT

这个RefCountBitsT里面有一个属性BitsType bits;

BitsType分为32位和64位,现在电脑基本都是64位,这个bits才是引用计数的核心东西。是一个无符号64位整型

所以InlineRefCounts目前就是一个uint64_t,被RefCountBitsT操作着

名字范围(起始位置,长度 )作用
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地址
SideTableUnusedLowBitsSideTable没有用到的低字节位数
SideTableMarkMask(62, 1)是否存放是SideTable


弱引用

swift_weakinit.

调用 nativeInit方法 ,

调用formweakreference

 然后是allocatesidetable方法

template <>
HeapObjectSideTableEntry* RefCounts<InlineRefCountBits>::allocateSideTable(bool failIfDeiniting)
{
//获取当前的引用计数存给oldbits
  auto oldbits = refCounts.load(SWIFT_MEMORY_ORDER_CONSUME);
  
  // oldbits中存放的可能已经是生成好的SideTable地址,所以判断一下,如果能取到SideTable,那么直接返回出去,因为已经创建过了
  if (oldbits.hasSideTable()) {
    // Already have a side table. Return it.
    return oldbits.getSideTable();
  } 
  //如果正在销毁中,那么直接返回空指针
  else if (failIfDeiniting && oldbits.getIsDeiniting()) {
    // Already past the start of deinit. Do nothing.
    return nullptr;
  }

  // Preflight passed. Allocate a side table.
  
  // 生成了SideTable存给变量side
  HeapObjectSideTableEntry *side = new HeapObjectSideTableEntry(getHeapObject());
  
  // 这个比较关键,这个方法把变量side的地址做了一定的操作,形成新的newbits,这个方法下面会详细讲
  auto newbits = InlineRefCountBits(side);
  
  do {
  //这里又判断oldbits里存的是否是SideTable,是的话,返回老的SideTable,删除刚才我们创建的SideTable,这个好像和开头重叠了,猜测可能是多线程的原因吧。
    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;
    }
    // 把当前的引用计数存入SideTable中
    side->initRefCounts(oldbits);
    //CAS
  } while (! refCounts.compare_exchange_weak(oldbits, newbits,
                                             std::memory_order_release,
                                             std::memory_order_relaxed));
  return side;
}

这个类就是sidetable的结构

class HeapObjectSideTableEntry {
  // FIXME: does object need to be atomic?
  std::atomic<HeapObject*> object;
  SideTableRefCounts refCounts;
  ...
}

第一个是指向的对象,第二个是sidetable的引用计数,是SideTableRefCounts,没有弱引用的时候是InlineRefCounts。

参考文章和图片:Swift引用计数的底层分析 - 掘金

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值