iOS DeveloperInstrument工具iOS 你不知道的新鲜事

Xcode Instruments 检测循环引用的方法

2017-09-29  本文已影响551人  荔枝lizhi_iOS程序猿
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 方法。

demo 代码 https://github.com/lizhi0123/CycleLeak

上一篇下一篇

猜你喜欢

热点阅读