[Swift通天遁地]七、数据与安全-(11)如何检测应用程序中的内存泄露

本文将演示使用Instruments Allocations工具检测应用程序中的内存泄漏问题。

内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

在项目文件夹【DemoApp】上点击鼠标右键,弹出右键菜单。

【New File】->【Swift File】->【Next】->【Save As】:People.swift->【Create】

 1 import Foundation
 2 //主人类
 3 class People
 4 {
 5     //名称属性
 6     var name : String
 7     //主人的宠物
 8     var pet : Pet?
 9     
10     //添加一个初始化方法,并以名称作为参数
11     init(name:String)
12     {
13         //设置对象的名称属性
14         self.name = name
15         //初始化日志
16         print("People is initialized.")
17     }
18     
19     //添加一个析构方法
20     deinit
21     {
22         //析构日志
23         print("People is deinitialized.")
24     }
25 }

使用相同的方式创建另一个类文件【Pet.swift】 

 1 import Foundation
 2 //宠物类
 3 class Pet
 4 {
 5     //名称属性
 6     var name : String
 7     //宠物的主人属性
 8     var master : People?
 9     
10     //添加一个初始化方法,并以名称作为参数
11     init(name:String)
12     {
13         //设置名称属性
14         self.name = name
15         //输出初始化日志
16         print("Pet is initialized.")
17     }
18     
19     //添加一个析构方法
20     deinit
21     {
22         //析构日志
23         print("Pet is deinitialized.")
24     }
25 }

在项目导航区,打开视图控制器的代码文件【ViewController.swift】 

 1 import UIKit
 2 
 3 class ViewController: UIViewController {
 4 
 5     override func viewDidLoad() {
 6         super.viewDidLoad()
 7         // Do any additional setup after loading the view, typically from a nib.
 8         
 9         //添加一个按钮,当用户点击该按钮时,创建主人对象和宠物对象。
10         let button = UIButton(frame: CGRect(x: 0, y: 0, width: 280, height: 44))
11         //将按钮控件放置在根视图的中心位置
12         button.center = self.view.center
13         //设置正常状态下的标题文字
14         button.setTitle("PeopleAndPet", for: .normal)
15         //设置按钮的背景颜色为橙色
16         button.backgroundColor = UIColor.orange
17         //给按钮绑定点击事件
18         button.addTarget(self,
19                          action: #selector(ViewController.peopleAndPet), 
20                          for: UIControl.Event.touchUpInside)
21         
22         //设置根视图的背景颜色
23         self.view.backgroundColor = UIColor.orange
24         //并把按钮控件添加到根视图
25         self.view.addSubview(button)
26     }
27     
28     //添加一个方法,用来响应按钮的点击事件
29     @objc func peopleAndPet()
30     {
31         //添加一个主人对象和一个宠物对象
32         var master:People?
33         var dog:Pet?
34         
35         //对两个对象进行初始化操作,并设置它们的名称属性。
36         master = People(name: "Jerry")
37         dog = Pet(name: "Dog")
38         
39         //设置主人的宠物属性
40         //设置宠物的主人属性
41         //使两个对象相互引用,
42         //由于两个对象互相引用,所以两个对象并不会在内存中被释放。
43         master!.pet = dog        
44         dog!.master = master       
45 
46         //将两个对象置空
47         master = nil
48         dog = nil
49     }
50 
51     override func didReceiveMemoryWarning() {
52         super.didReceiveMemoryWarning()
53         // Dispose of any resources that can be recreated.
54     }
55 }

启动按钮右下角箭头选择:【Build for Profiling】性能分析构建选项

此时将进入性能分析窗口,在【Instrument Detail】过滤输入框内,输入类名:People

由于尚未创建主人对象,所以在内存分配摘要列表中的搜索结果为空。

使用【Alt】+【Tab】切换至自动打开的模拟器窗口,

点击模拟器中创建的应用程序按钮。

由于两个对象互相引用,所以两个对象并不会在内存中被释放。

此时在内存分配摘要列表中,显示了一条主人对象的内存分配记录。

选择该条内存分配记录。点击右侧的小箭头,显示内存分配的地址信息。

接着选择内存地址,点击右侧的【扩展细节图标】(感叹号样式)。

在列表中显示的堆栈序列,其中黑色的代码为开发者编写的代码。

鼠标双击黑色的代码,在左侧区域显示该代码。

点击代码界面右上角的开发软件图标,,打开Xcode.

现在来修改People类,将Pet对象的引用修改为弱引用,

以解决内存泄露的问题。

 1 import Foundation
 2 //主人类
 3 class People
 4 {
 5     //名称属性
 6     var name : String
 7     //主人的宠物
 8     //将宠物对象的引用修改为弱引用。
 9     //就不会产生内存泄露的问题。
10     weak var pet : Pet?
11     
12     //添加一个初始化方法,并以名称作为参数
13     init(name:String)
14     {
15         //设置对象的名称属性
16         self.name = name
17         //初始化日志
18         print("People is initialized.")
19     }
20     
21     //添加一个析构方法
22     deinit
23     {
24         //析构日志
25         print("People is deinitialized.")
26     }
27 }

在【Instrument Detail】过滤输入框内,输入类名:People

在内存分配摘要列表中,显示的搜索结果为空。

说明People对象和Pet对象,已经在内存中被正确的释放。

在默认情况下,显示的是已创建和被持有的内存分配,

勾选【Allocation Lifespan】区域的【All Allocations】所有的内存分配选项。

点击右侧的小箭头,显示内存分配的地址信息。

继续点击内存地址右侧的小箭头,查看内存分配的详细信息。

在内存分配列表中,显示了内存空间的创建时间,以及其他相关的信息。

选择【Static】->【Allocations List】内存分配列表选项。

然后在搜索框内,继续添加Pet类名。

点击输入框左侧的下拉箭头,弹出选项列表。

选择【Matches Any】匹配任意选项,查找和People对象和Pet对象有关的内存分配记录。

点击【Detail】细节标签,显示选项的列表。选择【Console】控制台选项。查询内存分配的日志信息,

此时在控制台输出了People对象和Pet对象,两者内存分配和回收的详细流水记录。

猜你喜欢

转载自www.cnblogs.com/strengthen/p/10331948.html