1、运行MemoryProblems后,运行崩溃出现EXC_BAD_ACCESS,启动NSZombieEnabled,选中Edit Scheme并点击,Run -> Diagnostics -> Enable Zombie Objects(悬挂指针的检测),设置完之后,再次运行和点击页面,虽然会再次crash,但这次控制台打印了有用信息,点击Continue program execution按钮继续运行,对比找到相同地址并修改(启动MallocStackLogging)
常见原因:某变量被assign修饰,对变量值后,它的对象就马上释放,而变量也不是strong而是weak,此时仍然使用就会导致程序crash
2、手动静态分析:应用Product—>Analyze或快捷键shift + command + b进行内存泄漏的初步检测
自动静态分析:在Build Settings启用Analyze During 'Build',每次编译时都会自动静态分析
3、可以在xcode的build setting中打开implicit retain of ‘self’ within blocks,xcode编译器会给出警告,逐个排查警告
4、应用Leak Instrument进行内存泄露查找:点击Xcode的菜单栏的 Product -> Profile 启动Instruments,出现Instruments的工具集,选中Leaks子工具点击,点击红色圆点按钮启动Leaks工具,在Leaks工具启动同时,模拟器或真机也跟着启动,启动Leaks工具后,它会在程序运行时记录内存分配信息和检查是否发生内存泄露
首先点击Leak Checks时间条那个红色叉,点击红色叉后,下面显示Leaks By Backtrace,双击某行内存泄露调用栈,会直接跳到内存泄露代码位置
Leak Instrument有Cycles & Roots界面:Persistent Bytes和#Persistent。#Persistent是object的数量,也就是allocation的次数,而Persistent Bytes是具体的内存大小。#Persistent是我们需要关注的,内存有没有泄露也是看这个值是不是只增不减。
Allocations:启动Allocations,勾选列表最上边的,右边设置勾选:Discard unrecorded data upon stop、Identify virtual C++ objects、* isContain…Record
列表勾选VM
Generation Analysis
这个功能是非常有用的,一般是这样用的:进入一个页面前mark一下,在退出这个页面的时候再mark一下可以比较哪些内容增加了,就可以具体分析哪些内存没有被释放
Call Tree:需要我们把列表展示类型切换成Call Trees,能够非常清晰的看到调用树
Separate by Category:按照类别隔开,我们钩上看看效果
Separate by Thread:按照线程划分,我个人不是很喜欢这种划分,因为我不是很关心线程
Invert Call Tree:反转调用,我们给一张对比图就不需要解释了
Hide System Libraries:这个似乎是必钩的,因为我们目前只关心自己的方法,不关心系统的
Flatten Recursion:扁平化递归
Data Mining:数据挖掘,这是一个很具有噱头的功能
点击Symbol、Library会自动把你选中的行的符号、库加到小框中
符号和库有两个选项,就是是否过滤改行;点击Restore会去掉小框中的选中行
5、通过查看dealloc是否调用查看某个class是否泄漏问题
- (void)dealloc
{
NSLog(@"release XXXXViewController");
}
方法: __weak XXXXViewController *weakSelf = self;在Block里用weakSelf
常见问题:
1、UITextField在iOS 11内存泄漏问题:UITextField没释放原因使用secureTextEntry属性,解决方案
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if (textField == self.passWordTextField) {
textField.secureTextEntry = YES;
}else {
textField.secureTextEntry = NO;
}
return YES;
}
2、使用CGMutablePathRef path = CGPathCreateMutable();时出现Potential leak of an object stored into 'path’,解决方案
CGPathRelease(path);
以creat,copy作为关键字的函数都是需要释放内存的,注意配对使用。比如:CGColorCreate<-->CGColorRelease
3、The 'viewWillDisappear:' instance method in UIViewController subclass
XXX is missing a [super viewWillDisappear:] callm,解决方案
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
4、调用
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
方法之后在不需要NSTimer时及时调用[self.timer invalidate];千万不要在dealloc方法中调用,因为NSTimer强引用self,所以不会执行dealloc方法。
5、对象之间的循环引用:例子:两个ViewController都需要使用对方,这个时候可以用@class ;
说明:在 .h 中引入某个类, @class 指的是 当前文件 只是引入类名, 并没有使用类里面的东西. 想要在 .m 里面使用 类的内容的话, 还是要 #import <>, 这种情况跟 上面的对象之间的防止循环引 有点不一样
6、如果是C申请的内存,注意new delete, malloc free的配对处理。
7、图片相关:
缓存:imageNamed:
只需传入文件名.扩展名即可。
可以加载bundle中任意位置的图片,包括main bundle中其他bundle的。
imageNamed方法创建对象的步骤如下:
7.1根据图片文件名在缓存池中查找图片数据,如存在,则创建对象并返回;
7.2如果不存在,则从bundle中加载图片数据,创建对象并返回;
7.3如果相应的图片数据不存在,返回nil。
不缓存:imageWithContentsOfFile:
必须传入图片文件的全名(全路径+文件名)。
无法加载Images.xcassets中的图片。
对于大的图片且偶尔需要显示的应放到工程目录下,不要放到Assets.xcassets中;并使用imageWithContentsOfFile加载不让系统缓存
background.image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/*.png"]];
对于经常需要展示的小图片放到Assets.xcassets中让系统缓存,使用imageNamed加载
background.image = [UIImage imageNamed:@"*.png"];
不常用大图:将imageView.image = [UIImage imageNamed:nameArr[index]];
改为imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:nameArr[index] ofType:@"png"]];
8、出现VM:CG raster data,SDWebImage的问题
需要在Appdelegate中设置一下
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
[[SDImageCache sharedImageCache] setShouldCacheImagesInMemory:NO];
9、VM:CoreAnimation
Found out that animation caused by the inner pages.
Inside the pageViewController(viewController that added to the scrollView as a page) on viewWillDisappear:(BOOL)animated method I added this
for (CALayer* layer in [self.view.layer sublayers]) {
[layer removeAllAnimations];
}
it resolved the problem.
10、@property (readwrite, nonatomic, copy) NSMutableURLRequest *request;出现Property of mutable type 'NSMutableURLRequest' has 'copy' attribute; an immutable object will be stored instead,解决方案
@property (readwrite, nonatomic, strong) NSMutableURLRequest *request;