1.问题

你知道delegate 如果是strong 修饰的话,就会引起循环引用。导致内存释放不掉,内存泄漏。

你知道 :block 里,如果 用到 self 的话,就必须 先weak self ,如果不用的话就会导致内存释放不掉,内存泄漏。

但是 你知道 究竟怎么样 才能检测到循环引用 引起的内存泄漏吗?

怎么看我的代码究竟有没有 内存泄漏?

2 代码

下面我们就用Instrument 检测下 循环引用。更直观的感受下。

内存检测代码:

image.png

LeakController 里 调用 LeakImageView 显示图片。并设置 LeakImageView 的delegate, 注意 LeakImageView 的delegate 并未用weak 引用。会引起循环 应用。

LeakController 预览

image.png

LeakController 代码

//

// LeakController.swift

// Cycle

//

// Created by Sunny on 2017/9/29.

// Copyright © 2017年 Sunny. All rights reserved.

// 简书: http://www.jianshu.com/u/2dc174d83679

import UIKit

class LeakController: UIViewController {

@IBOutlet weak var leakImageView: LeakImageView!

override func viewDidLoad() {

super.viewDidLoad()

// 循环引用 代码

leakImageView.delegate = self //注销 此句 代码 可以 执行deinit, 否则不执行deinit

}

override func didReceiveMemoryWarning() {

super.didReceiveMemoryWarning()

// Dispose of any resources that can be recreated.

}

deinit {

print("释放 LeakController")

}

}

LeakImageView 预览

image.png

LeakImageView 代码

//

// LeakImageView.swift

// Cycle

//

// Created by Sunny on 2017/9/29.

// Copyright © 2017年 Sunny. All rights reserved.

// 简书: http://www.jianshu.com/u/2dc174d83679

import UIKit

class LeakImageView: UIImageView {

/// delegate 强引用 ,delegate 的实现方式就在此省去。

var delegate : AnyObject? ;

deinit {

print("释放 leakImageView")

}

}

准备工作已做好,现在开始检测

3.检测

循环引用是 因为不能释放掉ViewController ,所以永远不会执行 LeakController里的 “deinit” 方法

(1).instrument 启动 选择APP ,并选择Allocations。

image.png

(2).查看 Persistent (持久内存)

会发现Persistent 会从 0 一直涨。而且不减。我跳转了11次,此处就显示11。说明 现在存活的LeakController 为 11 个。但是 正常应该是显示 1 个。

循环引用的Persistent (如下图)

image.png

正常的Persistent (如下图)

Transient(短暂的,路过的) 是 使用过的LeakController;每使用并释放 一个Leakcontroller Transient都会增加1. 这个才是正常的。

image.png

总结:

不断的跳转,并返回时: 循环引用时 Persistent 会一直增长.; 且不会调用 deinit 方法。

正常情况下 Persistent 是正常使用的个数,本项目里是1.且会调用deinit 方法。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐