轻舞飞扬的玻璃纱 發表於 2020-8-17 16:05:00

iOS开发常见的内存泄漏有哪些情况?如何排查和避免?

<blockquote>
<p>面试题:常见的内存泄漏有哪些情况?如何排查和避免?</p>
</blockquote>
<p>内存泄漏原理:在百度上的解释就是“程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果”。</p>
<ul>
<li>
<h3>常见的内存泄漏情况:</h3>
<ul>
<li>
<p>情况一:对象之间的循环引用问题<br>循环引用的实质:多个对象相互之间有强引用,不能施放让系统回收。解决办法:使用&nbsp;<code>weak</code>&nbsp;打破对象之间的相互强引用</p>

</li>
<li>
<p>情况二:block的循环引用<br><code>block</code>在<code>copy</code>时都会对<code>block</code>内部用到的对象进行强引用的。解决办法使用:使用<code>__weak</code>打破循环的方法只在&nbsp;<code>ARC</code>下才有效,在&nbsp;<code>MRC</code>&nbsp;下应该使用<code>__block</code></p>

</li>

</ul>

</li>

</ul>
<div class="_2Uzcx_"><button class="VJbwyy" type="button"></button>
<pre class="line-numberslanguage-objectivec"><code class="language-objectivec">__weak <span class="token keyword">typeof<span class="token punctuation">(<span class="token keyword">self<span class="token punctuation">) weakSelf <span class="token operator">= <span class="token keyword">self<span class="token punctuation">; <span class="token keyword">self<span class="token punctuation">.myBlock <span class="token operator">= <span class="token operator">^<span class="token punctuation">(<span class="token punctuation">) <span class="token punctuation">{ <span class="token comment">// 除了下面的还有 调用 self的一些属性等等 };
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<ul>
<li>情况三: delegate 的循环引用<br><code>delegate</code>是委托模式.委托模式是将一件属于委托者做的事情,交给另外一个被委托者来处理,在这里我们可能会出现委托者和被委托人之间的相互强引用问题;解决办法:在声明&nbsp;<code>delegate</code>&nbsp;属性的时候 用<code>weak</code>&nbsp;进行弱引用 或者 通过中间对象(代理对象)的方式来解决(效率更加高的中间对象<code>NSProxy:</code>不需要进行发送消息和再动态解析,直接进行消息转发)</li>

</ul>
<div class="_2Uzcx_"><button class="VJbwyy" type="button"></button>
<pre class="line-numberslanguage-objectivec"><code class="language-objectivec"><span class="token keyword">@property<span class="token punctuation">(nonatomic<span class="token punctuation">, weak<span class="token punctuation">) id delegate<span class="token punctuation">;
</span></span></span></span></span></code></pre>
</div>
<ul>
<li>
<p>情况四:<code>CADisplayLink</code>、<code>NSTimer</code>会对<code>target</code>产生强引用,如果<code>target</code>又对它们产生强引用,那么就会引发循环引用;解决办法:<code>NSTimer</code>&nbsp;有一个<code>block</code>的方法,我们可以利用<code>block</code>的弱指针来解决<code>__weak typeof(self) weakSelf = self;</code>传&nbsp;<code>weakSelf</code>&nbsp;进去</p>
</li>
<li>
<p>情况五:通知的循环引用<br><code>iOS9</code>&nbsp;以后,一般的通知,都不再需要手动移除观察者,系统会自动在<code>dealloc</code>&nbsp;的时候调用&nbsp;<code>[ removeObserver: self]</code>。<code>iOS9</code>&nbsp;以前的需要手动进行移除。原因是:<code>iOS9</code>&nbsp;以前观察者注册时,通知中心并不会对观察者对象做&nbsp;<code>retain</code>&nbsp;操作,而是进行了&nbsp;<code>unsafe_unretained</code>&nbsp;引用,所以在观察者被回收的时候,如果不对通知进行手动移除,那么指针指向被回收的内存区域就会成为野指针,这时再发送通知,便会造成程序崩溃。从&nbsp;<code>iOS9</code>&nbsp;开始通知中心会对观察者进行&nbsp;<code>weak</code>&nbsp;弱引用,这时即使不对通知进行手动移除,指针也会在观察者被回收后自动置空,这时再发送通知,向空指针发送消息是不会有问题的。建议最好加上移除通知的操作:</p>

</li>

</ul>
<div class="_2Uzcx_"><button class="VJbwyy" type="button"></button>
<pre class="line-numberslanguage-objectivec"><code class="language-objectivec"><span class="token punctuation">(<span class="token keyword">void<span class="token punctuation">)dealloc <span class="token punctuation">{ <span class="token punctuation">[<span class="token punctuation"> removeObserver<span class="token punctuation">:<span class="token keyword">self<span class="token punctuation">.observer name<span class="token punctuation">:<span class="token string">@"name" object<span class="token punctuation">:nil<span class="token punctuation">]<span class="token punctuation">; <span class="token punctuation">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<ul>
<li>情况六:<code>WKWebView</code>&nbsp;造成的内存泄漏<br>总的来说,<code>WKWebView</code>&nbsp;不管是性能还是功能,都要比&nbsp;<code>UIWebView</code>&nbsp;强大很多,本身也不存在内存泄漏问题,但是,如果开发者使用不当,还是会造成内存泄漏。请看下面这段代码:</li>

</ul>
<div class="_2Uzcx_"><button class="VJbwyy" type="button"></button>
<pre class="line-numberslanguage-objectivec"><code class="language-objectivec"><span class="token keyword">@property <span class="token punctuation">(nonatomic<span class="token punctuation">, strong<span class="token punctuation">) WKWebView <span class="token operator">*wkWebView<span class="token punctuation">;

<span class="token operator">*   <span class="token punctuation">(<span class="token keyword">void<span class="token punctuation">)webviewMemoryLeak <span class="token punctuation">{ WKWebViewConfiguration <span class="token operator">*config <span class="token operator">=<span class="token punctuation">[<span class="token punctuation"> init<span class="token punctuation">]<span class="token punctuation">;
config<span class="token punctuation">.userContentController <span class="token operator">= <span class="token punctuation">[<span class="token punctuation"> init<span class="token punctuation">]<span class="token punctuation">;
<span class="token punctuation"><span class="token punctuation">;
_wkWebView <span class="token operator">= <span class="token punctuation">[<span class="token punctuation"> initWithFrame<span class="token punctuation">:<span class="token keyword">self<span class="token punctuation">.view<span class="token punctuation">.bounds configuration<span class="token punctuation">:config<span class="token punctuation">]<span class="token punctuation">;
_wkWebView<span class="token punctuation">.backgroundColor <span class="token operator">= <span class="token punctuation"><span class="token punctuation">;
<span class="token punctuation">[<span class="token keyword">self<span class="token punctuation">.view addSubview<span class="token punctuation">:_wkWebView<span class="token punctuation">]<span class="token punctuation">;
NSURLRequest <span class="token operator">*requset <span class="token operator">= <span class="token punctuation">(https://www.baidu.com/)"<span class="token punctuation">]<span class="token punctuation">]<span class="token punctuation">;
<span class="token punctuation"><span class="token punctuation">; <span class="token punctuation">} 这样看起来没有问题,但是其实 “addScriptMessageHandler” 这个操作,导致了 wkWebView 对 <span class="token keyword">self 进行了强引用,然后 “addSubview”这个操作,也让 <span class="token keyword">self 对 wkWebView 进行了强引用,这就造成了循环引用。解决方法就是在合适的机会里对 “MessageHandler” 进行移除操作:

<span class="token operator">*   <span class="token punctuation">(<span class="token keyword">void<span class="token punctuation">)viewDidDisappear<span class="token punctuation">:<span class="token punctuation">(BOOL<span class="token punctuation">)animated <span class="token punctuation">{ <span class="token punctuation">[<span class="token keyword">super viewDidDisappear<span class="token punctuation">:animated<span class="token punctuation">]<span class="token punctuation">;
<span class="token punctuation"><span class="token punctuation">; <span class="token punctuation">}

</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<ul>
<li>
<h3>内存泄漏的查询</h3>
</li>
<li>
<p>第一种查询方式:<code>Analyze</code>&nbsp;静态分析 (<code>command + shift + b</code>)也就是编译,主要分析以下四种问题:</p>
<ul>
<li>逻辑错误:访问空指针或未初始化的变量等;</li>
<li>内存管理错误:如内存泄漏等;</li>
<li>声明错误:从未使用过的变量;</li>
<li><code>Api</code>调用错误:未包含使用的库和框架。</li>
</ul>
</li>
<li>
<p>第二种查询方式:<code>Instruments</code>中的<code>Leak</code>动态分析内存泄漏,<code>product-&gt;profile -&gt;leaks</code>&nbsp;打开工具主窗口</p>
</li>
<li>
<p>第三种:<code>Facebook</code>早已开源了一款检测内存问题的三方库<code>FBRetainCycleDetector</code></p>
</li>
</ul>
<hr>
<p>更多:iOS面试题 答案合集</p><br><br>
来源:https://www.cnblogs.com/orang123/p/13518217.html
頁: [1]
查看完整版本: iOS开发常见的内存泄漏有哪些情况?如何排查和避免?