iOS内存泄漏自动检测工具PLeakSniffer
新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer)。
背景
前些天读到WeRead团队分享的一款内存泄漏检测工具,恍惚想起早些时候自己也有过编写这样一个小工具的想法,不知道由于什么原因把这事给忘记了。在仔细读过MLeaksFinder源码,了解实现思路之后,发现和自己最初的想法并不相同,终于在上个周末战胜拖延症将之前的想法付诸于代码,也就诞生了这款功能类似的内存泄漏检测工具PLeakSniffer。建议读者先详细阅读下 MLeaksFinder 这篇博客,详见文章底部阅读原文。
为什么要再造轮子
我在公司的项目里实际试用了MLeaksFinder,还查处了2处泄漏:sweat:。根据MLeaksFinder代码文件中日期推测,这个项目至少已开始半年有余,并在微信读书上得到了实践验证,在功能性和稳定性上都应该有不错的表现。
在编写完PLeakSniffer之后,查出了与MLeaksFinder相同的内存泄漏,思路迥异的代码抵达了相同的终点,写代码的乐趣莫过于此。新的思路或许还能抛砖引玉,如果激发更多的创意,也算是对iOS开发社区的一点小贡献。
MLeaksFinder现阶段能查处UIViewController和UIView的泄漏,我早先的想法还能递归的查出UIViewController之下所有Property的泄漏,并在PLeakSniffer及公司项目中得到了初步的验证,这算是对MLeaksFinder功能的一个小补充。
这类工具的意义
在我们讨论这类工具的意义之前,我们先得明确一点:
如果不使用Instrument当中的Leak检测工具,并没有什么轻易的100%精准的内存泄漏检测方式。
但这类工具还是有其存在价值的,内存泄漏的危害不用赘述,如果有一款工具能在80%的场景下检测出可能的内存泄漏,而且这种检测并不会带来任何副作用(不影响生产环境代码),为什么不使用它呢。
大部分人都低估了他们写代码时导致意外内存泄漏的可能性。Retain Cycle,Block强引用,NSTimer释放不当,这些常见的错误还是很容易出现在我们的代码里,Instrument每使用一次要费些精力,适合做定期的大排查。平常时候就更适合用MLeaksFinder,PLeakSniffer这类工具来做实时监控,提供免费建议。
PLeakSniffer实现思路
我们绝大部分时候都是在编写UIViewController,UIViewController就像一个根节点,持有并管理着很多的子节点对象,这些子节点的生命周期都依赖于Controller,Controller释放的时候,他们也随之释放。用一张图简单的描述他们的关系:
根据各个应用使用的设计模式不同(MVC,MVP,MVVM等),Controller所持有的Property也不相同。这里我们使用MVP作为例子,Controller所包含的对象就包括各种View对象,和Presenter,Model对象。当然每个对象又有可能持有更多的子对象。
PLeakSniffer基于这样一个假设: > 如果Controller被释放了,但其曾经持有过的子对象如果还存在,那么这些子对象就是泄漏的可疑目标。
当然这个假设并不是一个100%适用的真理,不同工程师编写代码的方式风格差别很大,有些会把某些UIViewController做成单例(个人觉得这不是个好主意。。),有些会把某些View缓存起来(即使Controller已被释放),还会有其他考虑不到的场景。但在80%以上的场景,我们在Controller结束生命周期之后会将其持有的资源一并释放。这时候PLeakSniffer可以发挥用处,给你一些免费的泄漏建议。
那么怎么在Controller被释放之后,知道其持有的对象没有被释放呢?
一个小技巧可以达成这个目标:子对象(比如view)建立一个对controller的weak引用,如果Controller被释放,这个weak引用也随之置为nil。那怎么知道子对象没有被释放呢?用一个单例对象每个一小段时间发出一个ping通知去ping这个子对象,如果子对象还活着就会一个pong通知。所以结论就是:如果子对象的controller已不存在,但还能响应这个ping通知,那么这个对象就是可疑的泄漏对象。完整的结构可以用下图表示:
通知移除需要一个时机,这里我们使用Associated Object机制给每一个子对象再生成一个Proxy对象,在Proxy对象的dealloc里面移除通知。
当然什么时候去判断一个对象的生命周期开始,什么时候判断为结束,需要一个精挑细选的机制。View,Controller,Property各不相同。
PLeakSniffer采取保守的策略,通过Objective C的runtime机制,递归的将一个Controller所有强引用的property找出,并安装proxy监听Ping通知。在我的测试下,基本上能将property泄漏的场景找出。
PLeakSniffer的使用方式很简答,通过Pod安装后,通过以下代码激活即可。
#if MY_DEBUG_ENV[[PLeakSniffer sharedInstance] installLeakSniffer];
[[PLeakSniffer sharedInstance] addIgnoreList:@[@"MySingletonController"]];#endif
addIgnoreList可以添加一些特殊的忽略名单,比如单例这种无法正确预测泄漏的对象。切记用Debug的宏将上述代码包住,不要把这些检测泄漏的代码带进线上环境。
如果检测到可疑泄漏,PLeakSniffer会在控制台打印一条日志:
Controller泄漏:Detect Possible Controller Leak: %@
其他对象泄漏:Detect Possible Leak: %@
更多的细节请查阅代码: GitHub地址 (https://github.com/music4kid/PLeakSniffer)。
iOS内存泄漏自动检测工具PLeakSniffer的更多相关文章
- 浅谈C++ 内存泄漏及其检测工具
浅谈C++ 内存泄漏及其检测工具 http://wenku.baidu.com/link?url=1DGkOOvd_ITZyB8IHAwfhCOx2tfO6id8UfuyQkAMHZU6sasaAXz ...
- [转载]浅谈C/C++内存泄漏及其检测工具
http://dev.yesky.com/147/2356147_3.shtml 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如Sm ...
- 【内存泄漏】 C/C++内存泄漏及其检测工具
对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Po ...
- C++内存泄漏及检测工具详解
#include "stdafx.h" #ifdef _DEBUG #define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, ...
- C/C++内存泄漏及检测 转
C/C++内存泄漏及检测 2011-02-20 17:51 by 吴秦, 30189 阅读, 13 评论, 收藏, 编辑 “该死系统存在内存泄漏问题”,项目中由于各方面因素,总是有人抱怨存在内存泄漏, ...
- [转]浅谈C/C++内存泄露及其检测工具
转自:http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问 ...
- C++中内存泄漏的检测方法介绍
C++中内存泄漏的检测方法介绍 首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck, ...
- C/C++内存泄露及检测工具
内存泄漏的定义 一般我们常说的内存泄漏是指堆内存的泄漏.堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内 存.应用程序一般使用malloc,re ...
- CPP-基础:内存泄露及其检测工具
[转]浅谈C/C++内存泄露及其检测工具 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garba ...
随机推荐
- 【HDU 3709】 Balanced Number (数位DP)
Balanced Number Problem Description A balanced number is a non-negative integer that can be balanced ...
- 自定义滚轮效果选择器spinnerwheel的使用总结
项目中有使用到像IOS滚轮效果的选择时间或数字的组件:android-spinnerwheel github地址:https://github.com/ai212983/android-spinner ...
- TDBGrideh表头自动排序设置
自动显示标题行的升降排序标志符(▽降序△升序)并做相应排序DBGridEh组件可以在标题行单元格中显示小三角形升.降排序标志符图片,在运行时可点击标题行,图片自动切换并做相应排序. 具体属性设置如下: ...
- Hadoop RPC简单实例
1.导入Hadoop-Common-2.6.0.jar导入工程,里面的IPC实现RPC需要的文件. 2.服务器端 (1)服务接口 package com.neu.rpc.server; /** * ...
- 【转】修改eclipse中的M2_REPO变量
转自:http://superseven.iteye.com/blog/1625429 从eclipse中增加了maven2的插件之后,maven默认的本地库的路径是${user}/.m2/repos ...
- linux中替换目录下的某个文件中包含的IP地址
#!/bin/bash #set -x oldIP=172.17.39.135 newIP=172.17.98.115 homefile=/usr/local/ims/ filelist=`grep ...
- Windows Phone8开发工具包简述(转载)
Windows Phone 软件开发包 (SDK) 8.0 可为您提供开发 Windows Phone 8 和 Windows Phone 7.5 应用和游戏所需的工具. 概述Windows Phon ...
- c++通过jnihelper调用java方法刷新androidUI的注意事项
2dx android项目需接入第三方sdk完成支付,玩家点击充值界面,通过jnihelper来调用java的方法并弹出android组件界面,之前采用直调的简单方法,顺利的把参数传到java层,但后 ...
- .net常見面試題(四)
1. .Net.C#.VisualStudio之间的关系是什么? .Net一般指的是.Net Framework,提供了基础的.Net类,这些类可以被任何一种.Net编程语言调用,.Net Frame ...
- MySQL开启远程链接(2014.12.12)
MySQL默认是关闭远程链接的,只能通过localhost访问本地数据库 如果不是本地访问就需要打开MySQL的远程连接: 基本步骤其实很简单: 1.进入mysql 2.依次运行下面的命令(黄色的为命 ...