本文主要介绍swift中的内存管理,涉及引用计数、弱引用、强引用、循环引用、Runtime等

内存管理 - 强引用
在swift中也是使用ARC来追踪和管理内存的,下面我们通过一个案例来进行分析
class CJLTeacher {
var age: Int = 18
var name: String = "CJL"
}
var t = CJLTeacher()
var t1 = t
var t2 = t
-
查看t的内存情况,为什么其中的refCounts是0x0000000600000003?

在分析类时(参考这篇文章Swift-进阶 02:类、对象、属性)有这么一个类HeapObject,下面继续通过这个类来分析t的引用计数
- 分析源码
HeapObject -> InlineRefCounts
struct HeapObject {
HeapMetadata const *metadata;
SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
...
}
👇
#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS \
InlineRefCounts refCounts
- 进入
InlineRefCounts定义,是RefCounts类型的别名,而RefCounts是模板类,真正决定的是传入的类型InlineRefCountBits
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
👇
template <typename RefCountBits>
class RefCounts {
std::atomic<RefCountBits> refCounts;
...
}
- 分析
InlineRefCountBits,是RefCountBitsT类的别名
typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
- 分析
RefCountBitsT,有bits属性
template <RefCountInlinedness refcountIsInline>
class RefCountBitsT {
...
typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::Type
BitsType;
...
BitsType bits;
...
}
👇
template <>
struct RefCountBitsInt<RefCountNotInline, 4> {
//类型
typedef uint64_t Type;
typedef int64_t SignedType;
};
其中bits其实质是将RefCountBitsInt中的type属性取了一个别名,所以bits的真正类型是uint64_t即64位整型数组
然后来继续分析swift中对象创建的底层方法swift_allocObject
- 分析初始化源码
swift_allocObject
static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
size_t requiredSize,
size_t requiredAlignmentMask) {
...
new (object) HeapObject(metadata);
...
}
👇
<!--构造函数-->
constexpr HeapObject(HeapMetadata const *newMetadata)
: metadata(newMetadata)
, refCounts(InlineRefCounts::Initialized)
{ }
- 进入
Initialized定义,是一个枚举,其对应的refCounts方法中,
enum Initialized_t { Initialized };
//对应的RefCounts方法
// Refcount of a new object is 1.
constexpr RefCounts(Initialized_t)
: refCounts(RefCountBits(0, 1)) {}
从这里看出真正干事的是RefCountBits
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS开发交流群:130 595 548,不管你是小白还是大牛都欢迎入驻 ,让我们一起进步,共同发展!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
- 进入
RefCountBits定义,也是一个模板定义
template <typename RefCountBits>
class RefCounts {
std::atomic<RefCountBits> refCounts;
...
}
所以真正的初始化地方是下面这个,实际上是做了一个位域操作,根据的是Offsets
LLVM_ATTRIBUTE_ALWAYS_INLINE
constexpr
RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)
: bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |
(BitsType(1) << Offsets::PureSwiftDeallocShift) |
(BitsType(unownedCount) << Offsets::UnownedRefCountShift))
{ }
分析RefCountsBit的结构,如下所示,

-
isImmortal(0)
-
UnownedRefCount(1-31):unowned的引用计数
-
isDeinitingMask(32):是否进行释放操作
-
StrongExtraRefCount(33-62):强引用计数
-
UseSlowRC(63)
重点关注UnownedRefCount和StrongExtraRefCount
-
将t的
refCounts用二进制展示,其中强引用计数为3
分析SIL代码
-
当只有t实例变量时

-
当有t + t1时,查看是否有
strong_retain操作
//SIL中的main
alloc_global @main.t1 : main.CJLTeacher // id: %8
%9 = global_addr @main.t1 : main.CJLTeacher : $*CJLTeacher // user: %11
%10 = begin_access [read] [dynamic] %3 : $*CJLTeacher // users: %12, %11
copy_addr %10 to [initialization] %9 : $*CJLTeacher // id: %11
//其中copy_addr等价于
- %new = load s*LGTeacher
- strong_retain %new
- store %new to %9

SIL官方文档中关于copy_addr的解释如下

- 其中的
strong_retain对应的就是swift_retain,其内部是一个宏定义,内部是_swift_retain_,其实现是对object的引用计数作+1操作
//内部是一个宏定义
HeapObject *swift::swift_retain(HeapObject *object) {
CALL_IMPL(swift_retain, (object));
}
👇
//本质调用的就是 _swift_retain_
static HeapObject *_swift_

本文深入探讨 Swift 中的内存管理,包括强引用、弱引用和循环引用,同时介绍了 Runtime 的相关概念如元类型、AnyClass 和 Self。通过实例分析了引用计数的工作原理,并提供了解决循环引用的方法。此外,文章还讨论了 Swift 与 Objective-C 在 Runtime 方面的交互,以及如何使用 Swift 的元类型进行类型操作。
最低0.47元/天 解锁文章
3万+

被折叠的 条评论
为什么被折叠?



