Swift中的内存管理:了解强引用,弱引用和未引用

在我们正在执行的所有编码的背后,您可能在编写代码时注意到一些变量,它们引用了strongweakunowned 。 他们到底是什么意思? 通过以strong为参考声明所有变量,是否会使您的变量更强?

strongweakunowned的用法实际上与Swift中称为自动引用计数(ARC)的内存管理有关。 让我们放慢一点,尝试了解这里的含义。 因此,ARC实际上会进行自动引用计数。 在计算机科学的定义中, 引用计数是一种将引用,指针或句柄的数量存储到资源(例如对象,块或内存,磁盘空间或其他资源)中的技术。 简而言之,ARC实际上有助于将引用存储到内存中,并有助于在不使用引用时进行清理。

另外,在这种情况下,引用计数仅适用于类的实例,不适用于结构和枚举,因为它们都是值类型,而不是引用类型。

在进一步介绍之前,为什么内存管理这么重要? 由于内存管理在分配内存中起着巨大的作用,因此程序确实可以在用户的​​请求下执行,并且在不再需要时可以免费重用,因此这确实是一个大问题。

但是,如果您耗尽内存,会发生什么呢?

  1. 该任务将停止执行,这意味着您将无法执行任何任务。
  2. 该任务可能不会继续执行,但会继续运行,直到达到极限并且程序崩溃为止。
  3. 您可能不希望用户使用越野车程序。

什么是自动引用计数(ARC)?

如官方文档中所述,

内存管理在Swift中“行之有效”,您无需自己考虑内存管理。 当不再需要类实例使用的实例时,ARC会自动释放它们。

ARC还跟踪信息,例如了解代码之间的关系,因此ARC能够有效地管理内存资源。

ARC如何工作?

每次通过init()创建类实例时,ARC都会自动分配一些内存来存储信息。 更具体地说,该内存块保存实例以及属性值。 当不再需要该实例时,将调用deinit()并且ARC将释放该实例的内存空间。

使用下面的代码,这很容易解释,但是我仍然希望您了解代码的作用。 这是带有Person实例和Gadget实例的两个类的示例, Gadget具有init方法,该方法将设置实例的属性,这意味着将任何信息分配到内存中。 同样,在deinit ,我们将看到实例被释放,这意味着包含信息的内存将在我们的情况下释放。

强vs弱vs无主-事实

  1. 通常,在创建属性时,除非引用被声明为weakunowned否则引用为强。
  2. 将属性标记为weak ,它将不会增加引用计数
  3. 介于两者之间的是unowned引用,它们既不是强引用,也不是可选类型。 编译器将假定对象没有被释放,因为引用本身仍然保持分配状态。

强大的参考

让我们看下面的例子。 我们有一个Person类型的变量,其引用为“ Kelvin”,一个Gadget类型的变量,其引用为“ iPhone 8 Plus”。

查看控制台消息。 您应该看到两个变量都已正确初始化。

现在,添加以下代码kelvin分配iphone并设置iphoneowner 。 在将kelviniphone设置为nil之前,请确保插入代码:

好的,在Playgrounds中再次运行代码。 您应注意,控制台仅显示有关初始化的消息。

显然,当我们中断强引用时,引用计数不会降为零,并且实例也不会被ARC释放。 为什么? 让我直观地说明这个问题。 即使在kelviniphone都设置为nil情况下, Person实例和Gadget实例之间的强引用也会保留并且不能被破坏。

这就是我们所说的强参考周期,导致您的应用程序内存泄漏。 为了打破强引用周期并防止内存泄漏,您将需要使用weak引用和未unowned引用。

参考不足

弱引用始终被声明为可选类型,因为变量的值可以设置为nil 。 为了指示引用为弱引用,您只需在属性或变量声明之前添加weak关键字,如下所示:

如您所见,控制台消息中,两个变量现在都已正确释放。 将owner变量更改为weak ,两个实例之间的关系看起来与前一个实例略有不同:

使用weak引用,当您将kelvin设置为nil ,可以正确地释放该变量,因为不再有指向Person实例的强引用。

无人参考

无主引用与弱引用非常相似,可用于解决强引用循环。 最大的区别在于,无主引用始终具有价值。 ARC不会将未拥有的引用的值设置为nil 。 换句话说,引用被声明为非可选类型。

仅当确定引用始终引用尚未取消分配的实例时,才使用无主引用。 如果在释放该实例后尝试访问一个未拥有的引用的值,则会收到运行时错误。

由于无主引用不能是可选的,因此我们将对示例代码进行一些修改:

让我们尝试通过将kelvin变量声明为nil来打破强引用,然后看看会发生什么。

如您所见, PersonGadget的实例已正确释放。 由于我们打破了Person实例的强引用(即kelvin ),因此实例被释放。 因此,由于没有对Gadget实例的强烈引用,它会自动释放。

结论

希望您现在对强项,弱项和无主引用有更好的了解。 Xcode为开发人员提供了内置工具来调试内存问题。 例如,如果要检测内存泄漏,可以转到菜单并选择“产品”>“配置文件”>“泄漏”。 如果您想让我们写更多有关内存管理和调试技巧的信息,请给我们留言并告知我们。