Swift-强引用&弱引用

2021-03-08 14:22:24 浏览数 (1)

强引用

Strong-RefCount

class Test{

var age: Int = 20

}

var t = Test()

var t1 = t

var t2= t

那么就有三个强引用指向当前的实例对象

InlineRefCountBits

引用计数里专门为了两个类型起了别名

typedef typename RefCountBitsInt<refcountIsInline, sizeof(void *)>::Type BitsType

typedef typename RefCountBitsInt<refcountIsInline, sizeof(void *)>::Type SingedType SignedBitsType

那么结构体里的是什么有价值的东西,值得swift另起别名

typedef uint64_t Type;

typedef int64_t SignedType;

//"Bitfield" accessors bit文件访问者

BiteType bits

那么bits就是一个64位整型的数据

在上一篇Swift文章中,列举过Swift对象初始化会传递的两个参数,一个是metadata,另一个是refCount

enum Initialized_t

// Refcount of a new object is 1 为新对象添加1引用计数

constexpr RefCounts(Initialized_t):refCounts(RefCountBits(0,1))

RefCountBits传入了0,1 这两个参数有什么作用?

RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)

RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)

:bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) | (BitsType(unownedCount) << Offsets::UnownedRefCountShift))

可以发现,传入的两个参数0,1做了位操作

那么上面这步复杂的操作为了下面这张图的存放位置

1-11-1

在lldb上输入

po t

x/8g $0

那么第二段内存地址所表达的东西就很明显了,分别是UnownedRefCount,StrongExtraRefCount

increment

static HeapObject *_swift_retain_ (HeapObject *object){

object->refCounts.increment(1)

那么increment方法做了什么事情?

increment

oldbits = refCounts.load(memory_order_consume) //传入一个内存指定的消费对象

RefCountBits newbits

newbits = oldbits

fast = newbits.incrementStrongExtraRefCount(inc)

if oldbits.isImmortal(){ return }

if SWIFT_UNLIKEY(!fast){return incrementSlow(oldbits ,inc)

}while(!refCounts.compare_exchange_weak(oldbits,newbits,memory_order_relaxed))

绕了一大圈,回到了RefCounts,

incrementStrongExtraRefCount

bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift)

bt打印的堆栈0x0000020000002 说明了就是上诉两个函数调用,位操作的结果

弱引用

NativeInit

side = object ? object->refCount.formWeakReferenct : nullptr

formWeakReference

auto side = allocateSideTable()

side->incrementWeak()

创建一个散列表allocateSideTable

HeapObjectSideTableEntry *side= new HeapObjectSideTabelEntry()

auto newbits = InlineRefCountBits(side)

好家伙,把side传给了在强引用时看见的InlineRefCountBits

回到强引用

RefCountBitsT

bits((reinterpret_cast<BitsType>(side) >> Offsets::SideTableUnusedLowBits)

| (BitsType(1) << Offsets::UseSlowRCShift)

| (BitsType(1) << Offsets::SideTableMarkShift)

)

位域操作想表达什么?

把散列表存到64位的某个位置

1-21-2

发现一对同兄难弟

typedef RefCounts<InlineRefCountBits> InlineRefCounts

typedef RefCounts<SideTableRefCountBits> SideTableRefCounts

强引用和弱应用一同指向了一个位置 RefCountBitsT 类型为uint64_t的bits

uint32_t weakBits

说明了RefCountBitsT存了强引用的bits也存储了弱引用计数

1-31-3

那么81e8存放的是对象,20087e02就是存放图1-2的地址

拿到该地址

1-41-4

把保留位63 62去掉

1-51-5

左移三位

1-61-6

拿到lldb里查看该地址信息

1-71-7

我们发现 43eff0 与对象地址是一样的

那么结果就出来了

0x10043f020 的前32位是强引用计数保存位置,后32位保存的是弱引用计数

0 人点赞