★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/10331948.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
本文将演示使用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, 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对象,两者内存分配和回收的详细流水记录。