Swift使用自动引用计数(ARC)来管理应用程序的内存使用。在大多是情况下,并不需要考虑内存的管理。当实例不再需要的时候,ARC会自动释放这些实例所使用的内存。

但ARC并不是绝对安全的。下面两种情况会发生内存泄露。
1,类实例之间的循环强引用
两个类实例都有一个强引用指向对方,这样的情况就是强引用循环,从而导致内存泄露。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Teacher {
    var tName : String
    var student : Student?
     
    init(name:String){
        tName = name
        println("老师\(tName)实例初始化完成")
    }
     
    deinit{
        println("老师\(tName)实例反初始化完成")
    }
}
 
class Student {
    var sName : String
    var teacher : Teacher?
     
    init(name:String){
        sName = name
        println("学生\(sName)实例初始化完成")
    }
     
    deinit{
        println("学生\(sName)实例反初始化完成")
    }
}
 
//测试开始
var teacher:Teacher?
var student:Student?
teacher = Teacher(name: "李老师")
student = Student(name: "刘同学")
teacher!.student = student
student!.teacher = teacher       
teacher = nil
student = nil
 
//测试结果(deinit未调用,则内存泄露)
老师李老师实例初始化完成
学生刘同学实例初始化完成

解决办法:使用弱引用

只需要将上述例子Teacher类的student变量加上关键字weak,或者将Student类的teacher变量加上关键字weak。

当A类中包含有B类的弱引用的实例,同时,B类中存在A的强引用实例时,如果A释放,也不会影响B的释放。但A的内存回收要等到B的实例释放后才可以回收。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Teacher {
    var tName : String
    weak var student : Student?
     
    init(name:String){
        tName = name
        println("老师\(tName)实例初始化完成")
    }
     
    deinit{
        println("老师\(tName)实例反初始化完成")
    }
}
 
class Student {
    var sName : String
    var teacher : Teacher?
     
    init(name:String){
        sName = name
        println("学生\(sName)实例初始化完成")
    }
     
    deinit{
        println("学生\(sName)实例反初始化完成")
    }
}

2,闭包引起的循环强引用

将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了实例,也会发生强引用循环。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class JsonElement{
    let name:String
    let jValue:String?
     
    lazy var asJson:() -> String = {
        if let text = self.jValue {
            return "\(self.name):\(text)"
        }else{
            return "text is nil"
        }
    }
     
    init(name:String, text:String){
        self.name = name
        self.jValue = text
        println("初始化闭包")
    }
     
    deinit{
        println("闭包释放")
    }
}
 
//开始测试
var p:JsonElement? = JsonElement(name: "p", text: "hangge.com")
println(p!.asJson())
p = nil
 
//测试结果(deinit未调用,则内存泄露)
初始化闭包
p:hangge.com

解决办法:使用闭包捕获列表

当闭包和实例之间总是引用对方并且同时释放时,定义闭包捕获列表为无主引用。但捕获引用可能为nil时,定义捕获列表为弱引用。弱引用通常是可选类型,并且在实例释放后被设置为nil。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class JsonElement{
    let name:String
    let jValue:String?
     
    lazy var asJson:() -> String = {
        [unowned self] in //使用无主引用来解决强引用循环
        if let text = self.jValue {
            return "\(self.name):\(text)"
        }else{
            return "text is nil"
        }
    }
     
    init(name:String, text:String){
        self.name = name
        self.jValue = text
        println("初始化闭包")
    }
     
    deinit{
        println("闭包释放")
    }
}

Swift - 内存泄露原因(循环强引用)及解决办法的更多相关文章

  1. 使用gc、objgraph干掉python内存泄露与循环引用!

    Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问 ...

  2. .Net内存泄露原因及解决办法

    .Net内存泄露原因及解决办法 1.    什么是.Net内存泄露 (1).NET 应用程序中的内存 您大概已经知道,.NET 应用程序中要使用多种类型的内存,包括:堆栈.非托管堆和托管堆.这里我们需 ...

  3. 解决Net内存泄露原因

    Net内存泄露原因及解决办法 https://blog.csdn.net/changtianshuiyue/article/details/52443821 什么是.Net内存泄露 (1).NET 应 ...

  4. 常见的Java Script内存泄露原因及解决方案

    前言 内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了 ...

  5. Swift-08-闭包引起的循环强引用

    循环强引用还会发生在当你将一个闭包赋值给类实例的某个实例,并且这个闭包体中又实用了这个类实例.这个闭包体重可能访问了实例的某个属性,例如self.**,或者闭包中调用了实例的某个方法,例如self.* ...

  6. C#项目间循环引用的解决办法,有图有真相

    C#项目间循环引用的解决办法,有图有真相 程序间的互相调用接口,c#禁止互相引用,海宏软件,20160315 /// c#禁止互相引用,如果项目[订单]中有一个orderEdit单元,要在项目[进销存 ...

  7. ubuntu安装vim时提示 没有可用的软件包 vim,但是它被其它的软件包引用了 解决办法

    ubuntu安装vim时提示 没有可用的软件包 vim-gtk3,但是它被其它的软件包引用了 解决办法 本人在ubuntu系统安装vim  输入 sudo apt-get install vim 提示 ...

  8. eclipse项目中关于导入的项目里提示HttpServletRequest 不能引用的解决办法

    eclipse项目中关于导入的项目里提示HttpServletRequest 不能引用的解决办法 当使用eclipse导入外部的web工程时,有时会提示HttpServletRequest, Serv ...

  9. [ Javascript ] 内存泄露以及循环引用解析

    内存泄露 在javascript中,我们非常少去关注内存的管理. 我们创建变量,使用变量,浏览器关注这些底层的细节都显得非常正常. 可是当应用程序变得越来越复杂而且ajax化之后,或者用户在一个页面停 ...

随机推荐

  1. CodeForces 508C Anya and Ghosts 贪心

    做不出题目,只能怪自己不认真 题目: Click here 题意: 给你3个数m,t,r分别表示鬼的数量,每只蜡烛持续燃烧的时间,每个鬼来时要至少亮着的蜡烛数量,接下来m个数分别表示每个鬼来的时间点( ...

  2. Irrlicht学习之光照的研究

    Irrlicht学习之光照的研究 最近研究一下Irrlicht的光照.发现Irrlicht的光照还是比较简单的,相比低于它的OpenGL和Direct3D,设置光源以及设置光照的参数更加人性化(可能是 ...

  3. 使用阿里云集成包快速搭建LAMP+FTP教程

    LAMP集成包安装步骤 1.下载开发集成包 下载最新版的阿里云市场提供的WEB开发集成包(内含Apache.Mysql.PHP.vsftpd) #Linux指令wget http://gongdan. ...

  4. JVM 指令集合

    指令码 助记符 说明 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int ...

  5. Chapter 14 观察者模式

    观察者模式又叫做发布-订阅模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 观察者模式所做的工作其 ...

  6. mojo 默认use utf8;

    my $endtime=strftime("%Y%m%d%H%M%S",localtime()); my $d=encode_utf8('验证'); if ($a3 =~/$d/) ...

  7. 【深圳,武汉】一加科技(One Plus)招聘,寻找不...

    [深圳,武汉]一加科技(One Plus)招聘,寻找不... [深圳,武汉]一加科技(One Plus)招聘,寻找不... 来自: 一加 2013-12-30 15:28:04         标题: ...

  8. UNIX网络编程——网络数据包检测

    网络数据包检测 数据包捕获(sniffer):是指在网络上进行数据收集的行为,需要通过网卡来完成. 三种访问方式: BSD Packet Filter(BPF) SVR4 Datalink Provi ...

  9. 一款简单的客户端安卓手机qq源码

    给大家分享一款比较简单的安卓手机qq应用源码,效果非常不错,大家可以借鉴一下,希望大家会喜欢. 1.png  (7.24 KB, 下载次数: 0) 02.png  (68.52 KB, 下载次数: 0 ...

  10. ZOJ3768 夹逼查找【STL__lower_bound()_的应用】

    首先学习一下lower_bound() 函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置.如果所有元素都小于val,则返回last ...