「这是我参与2022初次更文应战的第23天,活动概况查看:2022初次更文应战」
内存办理
Swift
言语连续了和Objective-C
言语一样的思路进行内存办理,都是采用引证计数
的方法来办理实例的内存空间;
主动引证计数
主动引证计数Automatic Reference Counting
也便是咱们常说的ARC
,其是Objective-C
言语与Swift
言语中处理内存办理问题的一种手段;在开发过程中,对类实例
进行不妥的引证将会造成内存泄漏
,当内存泄漏
堆集到必定程度就会给应用程序带来灾难性的成果;
Swift中关于引证计数的操作
咱们创立一个Person
类如下:
class Person {
var age: Int = 20
var name: String = "zhangSan"
}
接下来,咱们来打印剖析一下Person
的实例的内存指针:
咱们在之前的剖析中已经知道,其第二个8
字节存储的是refCounts
,也便是0x3
;在源码HeapObject.h
文件中,咱们能够找到HeapObject
结构体中关于refCounts
的界说:
剖析InlineRefCounts
能够发现,其是一个接纳InlineRefCountBits
泛型参数的模板类RefCounts
:
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
依据RefCounts
的界说咱们发现,其实质上是在操作咱们传递的泛型参数RefCountsBits
,而RefCounts
其实是对引证计数
的包装,而引证计数
的详细类型,取决于传递的参数类型InlineRefCountBits
;
咱们继续剖析InlineRefCountBits
的界说:
typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
其也是一个模板函数,而RefCountIsInline
其实便是true
:
enum RefCountInlinedness { RefCountNotInline = false, RefCountIsInline = true };
那么,咱们能够知道,引证计数终究操作的类其实是RefCountBitsT
:
咱们剖析RefCountBitsT
的过程中,发现只有一个bits
特点,而该特点是由RefCountBitsInt
的Type
特点界说的;而依据Type
的界说,咱们发现Type
其实是一个uint64_t
类型,是一个64位
的位域信息:
typedef uint64_t Type;
至此,咱们能够得到结论:
引证计数
本质上是一个64位
的位域信息,在这64位
信息中存储了引证计数
的相关信息;之所以这么做是为了将其笼统出来,提高代码复用率;
那么,问题来了,咱们创立一个新的实例对象时,他的引证计数是多少呢?从源码中咱们找到HeapObject
的初始化办法:
从HeapObject
的初始化实现中,咱们找到了refCounts
的赋值操作:
给refCounts
赋值了Initialized
,咱们继续剖析发现Initialized
是一个枚举类型Initialized_t
:
而依据源码显现,一个新的实例被创立时,传入的是RefCountBits(0,1)
,而RefCountBits
对应咱们上边剖析过的RefCountBitsT
,接下里,咱们在源码中找到RefCountBitsT
的初始化:
此时,依据传入的参数咱们能够剖析strongExtraCount
为0
,unownedCount
为1
;依据其实现咱们能够看到,是将strongExtraCount
(强引证计数)和unownedCount
(无主引证计数)通过位移的方法,存储在了64
位信息中;
在源码中咱们能够剖析如下:
# define shiftAfterField(name) (name##Shift + name##BitCount)
static const size_t PureSwiftDeallocShift = 0;
static const size_t PureSwiftDeallocBitCount = 1;
static const size_t StrongExtraRefCountShift = shiftAfterField(IsDeiniting);
static const size_t PureSwiftDeallocShift = 0;
static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
static const size_t IsDeinitingBitCount = 1;
static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
static const size_t UnownedRefCountBitCount = 31;
// 成果剖析
StrongExtraRefCountShift = shiftAfterField(IsDeiniting)
= IsDeinitingShift + IsDeinitingBitCount
= shiftAfterField(UnownedRefCount) + 1
= UnownedRefCountShift + UnownedRefCountBitCount + 1
= shiftAfterField(PureSwiftDealloc) + 31 + 1
= PureSwiftDeallocShift + PureSwiftDeallocBitCount + 31 + 1
= 0 + 1 + 31 + 1 = 33
通过上述计算,咱们能够剖析如下:
bits( (0 << 33) | (1 << 0) | (1 << 1))
bits( 0 | 1 | 2)
bit(3)
与咱们终究打印的0x3
相匹配;
64位
存储的信息如下:
第
0
位:标识是否是永久的
第1-31
位:存储无主引证
第32
位:标识当前类是否正在析构
第33-62
位:标识强引证
第63
位:是否运用SlowRC