iOS 测试 iOS 内存检测 MLeaksFinder 二次开发

xinxi · April 19, 2019 · Last by 雨夜狂奔 replied at April 30, 2019 · 4848 hits
本帖已被设为精华帖!

背景

在最近的iOS版本线上出现了两处内存泄漏并可能会导致OOM的风险,但是之前做专项测试并未发现.
iOS测试很多专项指标都是使用了xcode的instrument工具,那些泄漏检查使用的是leak工具.

目前使用leak工具的几个缺点:
1.泄漏数据不准
2.工具本身难用很卡
3.依赖手工测试使用,无法自动化.

奈何iOS也没有像Android LeakCanary这种工具.一次偶然的机会看到了腾讯开源了MLeaksFinder工具,号称能检查到view层的内存泄漏,并且对代码无侵入,本文就尝试把改该工具二次开发并且引入到项目中使用.

iOS相关知识

在正式进入正题之前,先来review一下iOS相关知识,比如生命周期、内存管理机制、内存泄漏原因.

iOS内存管理机制

MRC

MRC(manual reference counting)手动引用计数.

Xcode4.1及其以前版本没有ARC在开发项目时我们要自己使用引用计数来管理内存,比如要手动 retain、release、autorelease等.

eg:

int main(int argc, const char * argv[]) {
@autoreleasepool {
// 只要创建一个对象默认引用计数器的值就是1
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]); // 1

// 只要给对象发送一个retain消息, 对象的引用计数器就会+1
[p retain];

NSLog(@"retainCount = %lu", [p retainCount]); // 2
// 通过指针变量p,给p指向的对象发送一条release消息
// 只要对象接收到release消息, 引用计数器就会-1
// 只要一个对象的引用计数器为0, 系统就会释放对象

[p release];
// 需要注意的是: release并不代表销毁\回收对象, 仅仅是计数器-1
NSLog(@"retainCount = %lu", [p retainCount]); // 1

[p release]; // 0
NSLog(@"--------");
}
// [p setAge:20]; // 此时对象已经被释放
return 0;
}

从上面代码能看出来,MRC模式必须是遵循谁创建谁销毁对象的原则,否则就会造成对象未释放.

ARC

ARC(automatic reference counting)自引用用计数.只要程序中开启了ARC模式就不需要在retain、release、autorelease等方法.

view生命周期

iOS的view生命周期和Android的view生命周期类似,都有从创建到销毁的过程.

image

新建view

新建了一个view,继承UIViewController

image
`

重写了loadviewviewWillApperviewDidApper等方法

需要注意的是在dealloc放中,不需要[super dealloc]父类的方法,因为在ARC模式已经自动化开启了自动释放

image

展示生命周期数据

打印生命周期

image

view的跳转

push跳转

image

pop跳转

image

present跳转

image

pop返回

pop返回的需要获取当前堆栈的中页面,所以之前的页面应该在栈顶.

image

dismiss返回

present和dismiss一般是成对使用的.

image

制作一个内存泄漏

想要知道内存泄露怎么产生,最好的方法就是自己手写一个bug来尝试分析过程及原理.

写两个view来互相跳转,来判断有内存泄漏的迹象.

image

会提示: capturing self strongly in this block is likely to lead to a retain cycle

block对于其变量都会形成强引用(retain),对于self也会形成强引用(retain),而如果self本身对block也是强引用的话,就会形成强引用循环,无法释放——造成内存泄露.

image

image

image

在产生内存泄漏的时候,不会调用dealloc方法来时释放对象.

image

常见内存泄漏

Block循环引用

delegate循环引用

NSTimer循环引用

非OC对象内存处理

地图类处理

大次数循环内存暴涨

项目介绍

image

MLeaksFinder不需要在代码导入任何头文件,可以自动找到UIView 和UIViewController的内存泄漏.

这里使用了AOP技术,hook掉UIViewController和UINavigationController的pop跟dismiss方法.

集成

eg: podfile中导入MLeaksFinder

platform :ios, '9.0'
inhibit_all_warnings!
workspace 'SocketDemo.xcworkspace'
target "UICatalog" do

xcodeproj 'UICatalog.xcodeproj'
pod 'YYKit'
pod 'Aspects'
pod 'MLeaksFinder'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
puts "#{target.name}"
end
end

效果

image

正常情况下,ViewController pop/dismiss之后会被推出栈,进入ViewController的dealloc方法。如果没有走到dealloc方法中,则表明没有被释放,有内存泄露的现象.

缺点

  • c层内存泄漏无法找到.
  • 内存泄漏提示内容较少.

改造MLeaksFinder

MLeaksFinder在发生那些泄漏的时候是弹出提示框,我们需要在自动化或者手动测试中无感觉的把数据上报的测试平台中.需要改造如下:

我是直接clone的MLeaksFinder代码,所以没有在本地重新pod一个新项目.

  • 去掉弹框

    通过阅读代码发现MLeaksMessenger.m类中会在发生内存泄漏的时候回调alertWithTitle方法.
    并且会把内存泄漏的数据"message"参数传到方法体中.
    注释或者删除[alertViewTemp show]方法就会弹出弹框提示.

    image

  • 上报数据

    首先需要定义后端接口地址和接口需要接收到的字段,需要view名字、泄漏详情、版本、机型、系统、uid
    (后几个参数目前固定写死,后续再考虑怎么拿到动态参数)

    image

iOS发送网络请求可以使用AFNETWORK网络库或者NSURLSession网络库,NSURLSession的代码可以从postman中自动生成,直接复制代码即可.

image

提交代码

在原有的项目中把原.git文件删除,在自己的github中创建项目并且把代码push上去

image

podspec文件

spec文件即一个pod仓库的描述信息,git项目地址(上面创建的github地址)、项目名字、tag版本号、包含文件路径等等参数.

image

制作TAG

制作tag的目的是podspec文件中填写的tag对应的.框架发布成功之后,CocoaPods会根据tag 信息去获取相应代码.

git tag -a 1.0.0 -m 'my version 1.0.0'

git push origin --tags

本地使用pod repo

在项目中的podfile中写上pod名字和本地path路径.

eg:podfile

platform :ios, '9.0'
inhibit_all_warnings!
workspace 'SocketDemo.xcworkspace'
target "UICatalog" do

xcodeproj 'UICatalog.xcodeproj'
pod 'YYKit'
pod 'Aspects'
pod 'MLeaksFinder', :path => '/Users/xinxi/Documents/iOSProject/MLeaksFinder'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
puts "#{target.name}"
end
end

在项目下指定:pod install

image

注册pod

查看是否注册

pod trunk me

注册pod账号

pod trunk register xinxi@xxxx.com 'xinxi'  --verbose

image

再次执行pod trunk me

image

发布pod

cd MLeaksFinder

pod trunk push MLeaksFinder.podspec

image

安装pod

搜索制作好的pod

pod search MLeaksFinderNew

image

平台数据展示

image

结语

虽然本次二次开发的代码量很少,但是可以学习了到了iOS开发知识和内存泄漏的原因.

学习帖

手把手教你发布自己的 cocoapods 开源库

http://ios.jobbole.com/93284/

MLeaksFinder

https://github.com/Tencent/MLeaksFinder

ios中的view生命周期

https://www.jianshu.com/p/42eb5a930d66

iOS Viewcontroller及其他类对dealloc方法调用的理解

https://www.jianshu.com/p/89069ea78869

iOS学习心得之:MRC和ARC简单理解

https://www.jianshu.com/p/a16a4af3f5b9

MLeaksFinder:精准 iOS 内存泄露检测工具

https://wereadteam.github.io/2016/02/22/MLeaksFinder

iOS APP内存泄露问题解决

https://www.jianshu.com/p/3a79eb81ff0a

iOS之Block报错:capturing self strongly in this block is likely to lead to a retain cycle

https://blog.csdn.net/LVXIANGAN/article/details/50728577

共收到 1 条回复 时间 点赞
思寒_seveniruby 将本帖设为了精华贴 20 Apr 20:17

虽然看不懂,但是觉得楼主好优秀啊

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up