「这是我参与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的实例的内存指针

Swift(十五)-内存管理之引用计数

咱们在之前的剖析中已经知道,其第二个8字节存储的是refCounts,也便是0x3;在源码HeapObject.h文件中,咱们能够找到HeapObject结构体中关于refCounts的界说:

Swift(十五)-内存管理之引用计数

剖析InlineRefCounts能够发现,其是一个接纳InlineRefCountBits泛型参数的模板类RefCounts

typedef RefCounts<InlineRefCountBits> InlineRefCounts;

Swift(十五)-内存管理之引用计数

依据RefCounts的界说咱们发现,其实质上是在操作咱们传递的泛型参数RefCountsBits,而RefCounts其实是对引证计数的包装,而引证计数的详细类型,取决于传递的参数类型InlineRefCountBits

咱们继续剖析InlineRefCountBits的界说:

typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;

其也是一个模板函数,而RefCountIsInline其实便是true

enum RefCountInlinedness { RefCountNotInline = false, RefCountIsInline = true };

那么,咱们能够知道,引证计数终究操作的类其实是RefCountBitsT

Swift(十五)-内存管理之引用计数

咱们剖析RefCountBitsT的过程中,发现只有一个bits特点,而该特点是由RefCountBitsIntType特点界说的;而依据Type的界说,咱们发现Type其实是一个uint64_t类型,是一个64位的位域信息:

typedef uint64_t Type;

至此,咱们能够得到结论:

引证计数本质上是一个64位的位域信息,在这64位信息中存储了引证计数的相关信息;之所以这么做是为了将其笼统出来,提高代码复用率;

那么,问题来了,咱们创立一个新的实例对象时,他的引证计数是多少呢?从源码中咱们找到HeapObject初始化办法:

Swift(十五)-内存管理之引用计数

HeapObject的初始化实现中,咱们找到了refCounts的赋值操作:

Swift(十五)-内存管理之引用计数

refCounts赋值了Initialized,咱们继续剖析发现Initialized是一个枚举类型Initialized_t

Swift(十五)-内存管理之引用计数

而依据源码显现,一个新的实例被创立时,传入的是RefCountBits(0,1),而RefCountBits对应咱们上边剖析过的RefCountBitsT,接下里,咱们在源码中找到RefCountBitsT的初始化:

Swift(十五)-内存管理之引用计数

此时,依据传入的参数咱们能够剖析strongExtraCount0unownedCount1;依据其实现咱们能够看到,是将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位存储的信息如下:

Swift(十五)-内存管理之引用计数

0位:标识是否是永久的
1-31位:存储无主引证
32位:标识当前类是否正在析构
33-62位:标识强引证
63位:是否运用SlowRC