iOS开发-Swift进阶之内存管理 & Runtime!

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

本文主要介绍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_t64位整型数组

然后来继续分析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)

重点关注UnownedRefCountStrongExtraRefCount

  • 将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_
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值