面试题:常见的内存泄漏有哪些状况?如何排查和避免?web
内存泄漏原理:在百度上的解释就是“程序中已动态分配的堆内存因为某种缘由程序未释放或没法释放,形成系统内存的浪费,致使程序运行速度减慢甚至系统崩溃等严重后果”。面试
-
常见的内存泄漏状况:
-
状况一:对象之间的循环引用问题 循环引用的实质:多个对象相互之间有强引用,不能施放让系统回收。解决办法:使用
weak
打破对象之间的相互强引用app -
状况二:block的循环引用
block
在copy
时都会对block
内部用到的对象进行强引用的。解决办法使用:使用__weak
打破循环的方法只在ARC
下才有效,在MRC
下应该使用__block
框架
-
__weak typeof(self) weakSelf = self; self.myBlock = ^() { // 除了下面的还有 调用 self的一些属性等等 [weakSelf doSomething] };
- 状况三: delegate 的循环引用
delegate
是委托模式.委托模式是将一件属于委托者作的事情,交给另一个被委托者来处理,在这里咱们可能会出现委托者和被委托人之间的相互强引用问题;解决办法:在声明delegate
属性的时候 用weak
进行弱引用 或者 经过中间对象(代理对象)的方式来解决(效率更加高的中间对象NSProxy:
不须要进行发送消息和再动态解析,直接进行消息转发)
@property(nonatomic, weak) id delegate;
-
状况四:
CADisplayLink
、NSTimer
会对target
产生强引用,若是target
又对它们产生强引用,那么就会引起循环引用;解决办法:NSTimer
有一个block
的方法,咱们能够利用block
的弱指针来解决__weak typeof(self) weakSelf = self;
传weakSelf
进去工具 -
状况五:通知的循环引用
iOS9
之后,通常的通知,都再也不须要手动移除观察者,系统会自动在dealloc
的时候调用[[NSNotificationCenter defaultCenter] removeObserver: self]
。iOS9
之前的须要手动进行移除。缘由是:iOS9
之前观察者注册时,通知中心并不会对观察者对象作retain
操做,而是进行了unsafe_unretained
引用,因此在观察者被回收的时候,若是不对通知进行手动移除,那么指针指向被回收的内存区域就会成为野指针,这时再发送通知,便会形成程序崩溃。从iOS9
开始通知中心会对观察者进行weak
弱引用,这时即便不对通知进行手动移除,指针也会在观察者被回收后自动置空,这时再发送通知,向空指针发送消息是不会有问题的。建议最好加上移除通知的操做:性能
(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self.observer name:@"name" object:nil]; }
- 状况六:
WKWebView
形成的内存泄漏 总的来讲,WKWebView
无论是性能仍是功能,都要比UIWebView
强大不少,自己也不存在内存泄漏问题,可是,若是开发者使用不当,仍是会形成内存泄漏。请看下面这段代码:
@property (nonatomic, strong) WKWebView *wkWebView; * (void)webviewMemoryLeak { WKWebViewConfiguration *config =[[WKWebViewConfiguration alloc] init]; config.userContentController = [[WKUserContentController alloc] init]; [config.userContentController addScriptMessageHandler:self name:@"WKWebViewHandler"]; _wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; _wkWebView.backgroundColor = [UIColor whiteColor]; [self.view addSubview:_wkWebView]; NSURLRequest *requset = [NSURLRequest requestWithURL:[NSURL URLWithString:@"[https://www.baidu.com](https://www.baidu.com/)"]]; [_wkWebView loadRequest:requset]; } 这样看起来没有问题,可是其实 “addScriptMessageHandler” 这个操做,致使了 wkWebView 对 self 进行了强引用,而后 “addSubview”这个操做,也让 self 对 wkWebView 进行了强引用,这就形成了循环引用。解决方法就是在合适的机会里对 “MessageHandler” 进行移除操做: * (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [_wkWebView.configuration.userContentController removeScriptMessageHandlerForName:@"WKWebViewHandler"]; }
-
内存泄漏的查询
-
第一种查询方式:
Analyze
静态分析 (command + shift + b
)也就是编译,主要分析如下四种问题:atom- 逻辑错误:访问空指针或未初始化的变量等;
- 内存管理错误:如内存泄漏等;
- 声明错误:从未使用过的变量;
Api
调用错误:未包含使用的库和框架。
-
第二种查询方式:
Instruments
中的Leak
动态分析内存泄漏,product->profile ->leaks
打开工具主窗口代理 -
第三种:
Facebook
早已开源了一款检测内存问题的三方库FBRetainCycleDetector
指针
更多:iOS面试题 答案合集 更多:《BAT面试答案文集.PDF》,获取可加iOS技术交流圈:937194184,相互交流。code