面試題:常見的內存泄漏有哪些狀況?如何排查和避免?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