Swift(十六)-强引用与循环引用

681 阅读2分钟

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战

强引用

接下来上一篇文章内存管理之引用计数,我们对实例进行强引用,然后打印看一下内存数据的变化:

image.png

第一次强引用之后,内存数据中出现了2,这是因为第一次强引用之后,其保存在了高33位上:

image.png

相应的,第二次强引用之后,其再次左移,保存在了高34位上:

image.png

如果我们将代码修改如下:

image.png

p置为nil之后,内存数据出现了变化:

image.png

我们看到其32位上标识为1,也就是说明我们当前类没有了强引用,正在被析构

那么,就能强引用之后,底层究竟做了什么操作呢?我们通过汇编来分析一下,我们在即将进行强引用var p1 = p时进入汇编会发现如下的汇编代码:

image.png

在接下来的操作中,将会调用swift_retain方法,那么此方法是否就是我们要找的方法呢,我们进入源码查找此方法实现如下:

image.png

再次方法中,对refCounts进行了increment(1)操作:

image.png

将参数inc传入了incrementStrongExtraRefCount方法,其具体实现如下:

image.png

  • inc1
  • StrongExtraRefCountShift根据之前的计算为33

1 << 33为结果为8589934592,其对应的十六进制为0x200000000

image.png

与我们最初打印的内存数据相吻合;

循环引用

既然使用了强引用就极有可能会导致循环引用,我们来看下面代码:

image.png

通过Xcode控制台的打印信息可以看出,obj1obj2所占用的内存都没有被释放,尽管我们已经将obj1obj2都置为nil了;这便是循环引用最常出现的场景;

对于造成循环引用的实例,系统无法完成对其内存的释放和回收,那么在开发中我们如何避免和解决这种循环引用呢?

Swift中有两种方式来解决这个问题:

  • 弱引用
  • 无主引用

我们下篇文章进行介绍......