前边铺垫了那么多,现在终于要讲到垃圾回收这个东西了。
ARC
这不是方舟……这是自动引用计数(Automatic Reference Counting),这个东西是苹果用来管理内存的。
它的功能就是那个垃圾堆上的垃圾回收器。它能够保证所有在堆上运行的对象被释放后不会一直驻留在堆上。保证了那块内存会再分配给其他要使用的对象上。
何为释放
说到对象会不会被垃圾回收器给收走,那就要看引用会不会释放了:我们这样来分辨一个对象是否还在被使用——当没有引用再指向某个对象的时候,我们就说它已经被释放了——因为它再也不会被访问到了。
释放的方法
我们一般有三种方法可以释放掉对一个对象的引用:
- 把引用放在方法里,方法出栈,引用完蛋——对象没了引用,会被回收。
- 引用更改指向到其他对象上——原本的对象没有了引用,会被回收。
- 直接清空引用——前提是你声明的储存器是可选类型。
好了,现在我们分别来举几个栗子看:
1 2 3 4 5 |
func run() { _ = SmallGun(ammo1: 8, isSafe2: true) } run() |
方法执行完毕出栈,临时变量没了——对象自然就释放掉了。arc 发现对象没有引用了,那么这个对象就会被收回,留下的空间给别人用。
1 2 3 |
var gun1 = SmallGun(ammo1: 8, isSafe2: true) var gun2 = SmallGun(ammo1: 9, isSafe2: false) gun1 = gun2 |
我们吧 gun2 的引用赋给 gun1,那么 gun1原来的引用就被覆盖掉了,那对应的对象也就只能等着被回收啦!
1 2 3 |
var gun1:Gun? gun1 = SmallGun(ammo1: 8, isSafe2: true) gun1 = nil |
我们重新给 gun1 赋值为空,那么引用没了,对象也就随之完蛋了。
交叉引用
有这么一种情况,会导致自动引用计数捉鸡,我们来看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Aaa { var b:Gun? } var gun1:Gun? var aaa:Aaa? gun1 = SmallGun(ammo1: 8, isSafe2: true) aaa = Aaa() gun1?.ccc = aaa aaa?.b = gun1 aaa = nil gun1 = nil |
我们稍微修改了刚才的类,增加了一个 Aaa 类的引用属性,然后创建了这个 Aaa 的类,这个类包含了一个 Gun 类的引用属性,这时候我们把它两个互相引用,然后再释放掉……等等,真的可以释放掉吗?
然而并不能。
我们回顾一下一个对象被释放的定义:当对象没有引用就称作被释放——可是这两个对象都还有互相之间的引用呢!
所以,我们虽然访问不到这两个对象了,但是它们两个互相还引用着,arc 无计可施,你一样也不能再访问到它们——这就叫著名的“内存泄露”。
弱引用
这时候,我们要打破这个环路,让引用能够断开,这样才能让这个互相引用的对象一个一个地被释放掉。我们需要将其中一个声明为弱引用,只有这样才能让 arc 断开他们之间的环路。
1 2 3 |
class Aaa { weak var b:Gun? } |
这样就好了,环路会被打断,泄露的内存也被找回来了。
弱引用的要求
- 弱引用必须是变量,不能是常量,因为它得可以被修改。
- 弱引用必须是可选项,它得能被清空。
本文由 落格博客 原创撰写:落格博客 » 生存周期:自动引用计数
转载请保留出处和原文链接:https://www.logcg.com/archives/1135.html
Comments