Swift里你可能不知道的事儿(1)-Reference cycle引起的内存泄漏

Swift里你可能不知道的事儿(1)-Reference cycle引起的内存泄漏,第1张

概述Swift里你可能不知道的事儿(1) 泊学视频 泊阅文档 Reference cycle引起的内存泄漏 纵然Swift使用ARC(Automatic Reference Counting)为我们打理内存,这并不代表它面对任何情况都足够聪明。尤其是当对象之间存在相互引用的时候,更是容易由于reference cycle导致内存无法释放。当然,这并非我们本意,只是有时这样的问题发生的不甚明显。Swif Swift里你可能不知道的事儿(1)

泊学视频
泊阅文档

Reference cycle引起的内存泄漏

纵然Swift使用ARC(automatic Reference Counting)为我们打理内存,这并不代表它面对任何情况都足够聪明。尤其是当对象之间存在相互引用的时候,更是容易由于reference cycle导致内存无法释放。当然,这并非我们本意,只是有时这样的问题发生的不甚明显。Swift为我们提供了一系列语言机制来处理reference cycle,而我们也应该时刻保持警醒,避免内存泄漏。

*“ARC只针对类对象才生效,struct和enum都是值类型,它们的对象并不被ARC管理。”
特别提示*

ARC是如何工作的?

Swift使用“引用计数(reference count)”来管理类对象的生命周期,避免类对象在“仍被使用”的时候被意外释放。为了观察reference count、对象构建和对象释放之间的关系,我们先来定义一个类:

class Person {    let name: String        init(name: String) {        self.name = name        print("\(name) is being initialized.")    }        deinit {        print("\(name) is being deinitialized.")    }}

接下来,我们观察下面代码的的执行过程:

var ref1: Person?var ref2: Person?// Mars is being initialized.// count = 1ref1 = Person(name: "Mars")// count = 2ref2 = ref1// count = 1ref2 = nil// count = 0// Mars is being deinitialized.ref1 = nil

Person构造时,init被调用,只有一个变量引用了这个对象,此时的reference count为1;

当我们把ref1赋值给ref2时,它们指向相同的对象,此时的reference count为2;

当ref2为nil时,此时的reference count恢复为1;

当ref1为nil时,reference count为0,Tennat的deinit被调用,对象被释放;

在上面的例子里,由于ref1和ref2都会导致Person的reference count加1,因此它们叫做 strong reference 。这是Swift中的默认行为。

*“和带有Garbage Collection的语言不同,当一个对象的reference count为0时,Swift会立即删除该对象。”
特别提示*

理解Reference cycle是如何发生的

对于Person这样的单个对象,ARC可以很好的默默为我们工作。但是, 当不同类对象之间存在相互引用时 ,指向彼此的strong reference就会导致reference cycle。ARC无法释放它们之中的任何一个。来看一个例子,我们给Person添加一个Apartment:

class Person {    let name: String    var apartment: Apartment?        init(name: String) {        self.name = name        print("\(name) is being initialized.")    }        deinit {        print("\(name) is being deinitialized.")    }}class Apartment {    let unit: String    var tenant: Person?        init(unit: String) {        self.unit = unit        print("Apartment \(unit) is being initialized.")    }        deinit {        print("Apartment \(unit) is being deinitialized.")    }}

由于Person不一定会租Apartment,Apartment也不一定有房客,因此,Person.apartment和Apartment.tenant都是一个Optional,它们可以为nil。

接下来,我们分别创建一个Person和Apartment对象,然后把变量设置为nil,就可以看到Person和Apartment被构建和销毁了。

// Mars is being initialized// count = 1var mars: Person? = Person(name: "Mars")// Apartment 11 is being initialized// count = 1var apt11: Apartment? = Apartment(unit: "11")// count = 0// Mars is being deinitializedmars = nil// count = 0// apartment is being deinitializedapt11 = nil


接下来,如果我们让mars和apartment分别指向彼此:

// ... Create mars and apartment// mars.count = 2mars!.apartment = apartment// apartment.count = 2apt11!.tenant = mars// ... Set mars and apartment to nil

这时,尽管我们把mars和apt11设置为nil,Person和Apartmetn的deinit也不会被调用了。因为它们的两个member(apartment和tenant)是一个strong reference,指向了彼此,让对象仍旧“存活”在内存里。但是,mars和apt11已经被设置成nil,我们也已经无能为力了。这就是类对象之间的reference cycle。

接下来?

在理解了ARC的基本工作原理以及reference cycle的成因之后,我们将在接下来的一些列视频里,了解如何通过weak和uNowned reference来解决reference cycle。

总结

以上是内存溢出为你收集整理的Swift里你可能不知道的事儿(1)-Reference cycle引起的内存泄漏全部内容,希望文章能够帮你解决Swift里你可能不知道的事儿(1)-Reference cycle引起的内存泄漏所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1080615.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-27
下一篇 2022-05-27

发表评论

登录后才能评论

评论列表(0条)

保存