了解:在蘋果沒有出ARC(自動(dòng)內(nèi)存管理機(jī)制)時(shí),iOS開發(fā)攻城獅幾乎有一半的開發(fā)時(shí)間都消耗在怎么管理內(nèi)存上后來蘋果人性化推出了ARC,雖然在很大程度上幫助我們開發(fā)者節(jié)省了精力和時(shí)間。但是我們?cè)陂_發(fā)過程中,由于種種原因,還是會(huì)出現(xiàn)內(nèi)存泄漏的問題。
內(nèi)存泄漏是一個(gè)很嚴(yán)重的問題,我們先了解一下xcode7自帶的Instruments中的Leaks如何檢測(cè)我們的程序中內(nèi)存泄漏以及定位內(nèi)存泄漏代碼(Leaks分析內(nèi)存泄漏并不能把所有的內(nèi)存泄漏問題查出來,有的內(nèi)存泄漏時(shí)在運(yùn)行時(shí),用戶操作時(shí)才會(huì)產(chǎn)生的)
簡(jiǎn)介內(nèi)存管理:
- Object-C有3種內(nèi)存管理方式,他們分別是
- MRR (Manual Retain Release, 手動(dòng)保持釋放)
- ARC (Automatic Reference Counting,自動(dòng)引用計(jì)數(shù))
- GC (Garbage Collection,垃圾收集)
- 1> MRR
- ① 也稱為 MRC (Manual Reference Counting,手動(dòng)引用計(jì)數(shù))
- ② 由程序員自己負(fù)責(zé)管理對(duì)象生命周期,負(fù)責(zé)對(duì)象的創(chuàng)建和銷毀
- 2> ARC
- ① 采用和MRR一樣的內(nèi)存引用計(jì)數(shù)管理方式
- ② 在編譯時(shí)會(huì)在適合的位置插入對(duì)象內(nèi)存釋放,(如 release, autorelease, 和 retain 等)
- ③ 程序員不需要關(guān)心對(duì)象釋放的問題,蘋果推薦在新項(xiàng)目中使用ARC,但在iOS5之前的項(xiàng)目中不能采用ARC
- 3> GC
- ① 在Objective_C2.0之后,內(nèi)存管理出現(xiàn)了類似于Java和C#的內(nèi)存垃圾收集技術(shù),但是垃圾收集與ARC一直運(yùn)行,垃圾收集時(shí)后臺(tái)有一個(gè)線程負(fù)責(zé)檢查已經(jīng)不在使用的對(duì)象,然后釋放,
- ② 由于后臺(tái)有一個(gè)線程一直運(yùn)行,會(huì)嚴(yán)重影響性能,這也是java和C#程序的運(yùn)行速度無法超越C++的主要原因
- ③ GC技術(shù)不能應(yīng)用于iOS開發(fā),只能使用與Mac OS X開發(fā)
內(nèi)存泄漏
- 內(nèi)存泄漏指當(dāng)一個(gè)對(duì)象或變量在使用完成后沒有釋放掉,這個(gè)對(duì)象一直占用這部分的內(nèi)存,直到應(yīng)用停止
- 這種沒有釋放掉的對(duì)象多了內(nèi)存就會(huì)耗盡,其他應(yīng)用就無法運(yùn)行
- 內(nèi)存泄漏在C++,C和Objective-C的MRR中是比較普遍的問題
- 從理論上講,內(nèi)存泄漏是由對(duì)象或者變量沒有釋放引起的,但實(shí)踐證明并非所有的未釋放的對(duì)象或變量都會(huì)導(dǎo)致內(nèi)存泄漏,這與硬件環(huán)境和操作系統(tǒng)、系統(tǒng)環(huán)境有關(guān)
- 內(nèi)存泄漏導(dǎo)致我們軟件在運(yùn)行過程中占用越來越多的內(nèi)存,占有資源卻又得不到及時(shí)清理,會(huì)導(dǎo)致我們程序效率越來越低,反應(yīng)慢,會(huì)影響我們用戶體驗(yàn),失去市場(chǎng)的競(jìng)爭(zhēng)能力
iOS中查找漏點(diǎn)的工具
- 在xcode中,共提供兩種工具幫助查找泄漏點(diǎn),
- 1> Analyze
- 學(xué)名:靜態(tài)分析工具
- 查找:可以通過
product -> Analyze菜單項(xiàng)啟動(dòng) - 快捷鍵
CMD + Shift + b - Analyze主要分析一下四種問題
- 邏輯錯(cuò)誤:訪問空指針或?yàn)槌跏蓟淖兞康龋?/li>
- 內(nèi)存管理錯(cuò)誤:如內(nèi)存泄漏等;
- 聲明錯(cuò)誤:從未使用過的變量
- Api調(diào)用錯(cuò)誤:未包含使用庫(kù)和框架
- 2> Instruments
- 學(xué)名:動(dòng)態(tài)分析工具
- 查找:
product -> profile菜單項(xiàng)啟動(dòng) - 快捷鍵
CMD + i - 簡(jiǎn)介:它有很多跟跟蹤模塊可以動(dòng)態(tài)分析和跟蹤內(nèi)存,CPU和文件系統(tǒng)
- 1> Analyze
兩種工具查找漏點(diǎn)版本的介紹
- 1> 結(jié)合使用-思路分析:
- 先使用Analyze靜態(tài)分析查找可疑泄漏點(diǎn),在用Instruments動(dòng)態(tài)分析中的Leaks和Allocations跟蹤板塊進(jìn)行動(dòng)態(tài)跟蹤分析,確認(rèn)這些點(diǎn)是否泄漏,或者是否存有新的泄漏點(diǎn)出現(xiàn)等
- 2>使用 靜態(tài)檢測(cè)內(nèi)存泄漏問題 Analyze
-
在Analyze靜態(tài)分析結(jié)果中,凡是有圖標(biāo)出現(xiàn)的行都是工具發(fā)現(xiàn)的疑似泄漏點(diǎn)
疑似泄漏點(diǎn)所在行.png -
點(diǎn)擊疑似泄漏點(diǎn)行末尾的分叉圖標(biāo),會(huì)展開分析結(jié)果
展開分析結(jié)果.png -
檢測(cè)完成時(shí)的效果圖如下:
分析效果圖.png - 小結(jié):
- 這里使用Analyze靜態(tài)分析查找出來的泄漏點(diǎn),稱之為“可疑泄漏點(diǎn)”,之所以稱之為“可疑泄漏點(diǎn)”,是因?yàn)檫@些點(diǎn)未必一定泄漏,確認(rèn)這些點(diǎn)是否泄漏,還要通過Instruments動(dòng)態(tài)分析工具的Leaks和Allocations跟蹤模版,Analyze靜態(tài)分析只是一個(gè)理論上的預(yù)測(cè)過程
- 3> 動(dòng)態(tài)監(jiān)測(cè)Instruments的Leaks
- 1)CMD + i 打開
CMD打開.png -
2)打開頁(yè)面的介紹:
界面介紹.png - 在instruments中,雖然選擇了Leaks模版,但默認(rèn)情況下也會(huì)添加Allocations模版,基本上凡是內(nèi)存分析都會(huì)使用Allocations模版,它可以監(jiān)控內(nèi)存分布情況
- a. 選中Allocations模版,(圖1區(qū)域),右邊的3區(qū)域會(huì)顯示隨著十斤啊的變化內(nèi)存使用的折線圖,同時(shí)在4區(qū)域會(huì)顯示內(nèi)存使用的詳細(xì)信息,以及對(duì)象分配情況
- b. 點(diǎn)擊Leaks模版(圖中2區(qū)域)可以查看內(nèi)存泄漏情況。如果在3區(qū)域中有紅x出現(xiàn),則有內(nèi)存泄漏,4區(qū)域則會(huì)顯示泄漏的對(duì)象
- 3)打開Leaks進(jìn)行監(jiān)測(cè):
-
點(diǎn)擊泄漏對(duì)象可以在(下圖)看到它們的內(nèi)存地址,占用字節(jié),所屬框架和響應(yīng)方法等信息,打開擴(kuò)展視圖,可以看到右邊的跟蹤堆棧信息
leaks進(jìn)行監(jiān)測(cè).png -
4)監(jiān)測(cè)結(jié)果的分析:
監(jiān)測(cè)結(jié)果的分析.png - 5)Allocations—內(nèi)存分配版本的介紹
-
Allocations是監(jiān)測(cè)程序運(yùn)行過程中 內(nèi)存分配情況的,也需要同時(shí)運(yùn)行著程序。界面情況如下:
Allocations.png
Allocations .jpg - 雙擊某一個(gè)方法,同樣會(huì)跳轉(zhuǎn)到代碼中,會(huì)有每一句代碼對(duì)應(yīng)的內(nèi)存分配情況,根據(jù)這些信息,可以對(duì)程序里不同代碼的內(nèi)存占用情況有一些認(rèn)識(shí),并進(jìn)行針對(duì)性優(yōu)化
- 1)CMD + i 打開
具體使用
- 1>. Allocations紀(jì)錄了內(nèi)存分配,用來優(yōu)化內(nèi)存使用的
- 2>. Leaks用來分析內(nèi)存泄漏。ARC中引起的內(nèi)存泄漏原因就是引用環(huán)
-
第一步:先選擇Leaks和Leaks by Backtrace.這里可以看到那些對(duì)象內(nèi)訓(xùn)泄漏了,泄漏了多少,這個(gè)就是簡(jiǎn)單看看,沒有太多調(diào)試意義
監(jiān)測(cè)內(nèi)存泄漏多少.png -
第二步:然后看看Call Tree,因?yàn)镃all Tree會(huì)給我們大概的位置,有時(shí)候會(huì)給我們精確的位置,不過要看運(yùn)氣了。
然后,再右面選擇Invert Call Tree和Hide System Library
Call Tree.png - 雙擊上圖中的任意一行,就會(huì)跳到代碼處內(nèi)存泄漏的地方(事實(shí)上,到這步,很多內(nèi)存泄漏的問題都會(huì)被發(fā)現(xiàn)),當(dāng)然也有一些泄漏還是看不出來的
- 第三步
-
然后我們選擇對(duì)ARC調(diào)試很有用的一部分Circles & Roots,通過這個(gè)我們可以看到詳細(xì)的ARC引用計(jì)數(shù)過程。然后,我們看到如下圖
CirCles & Roots.png- 小的紅色矩形點(diǎn)擊可以看出引用計(jì)數(shù)的詳細(xì)信息(ARC就是自動(dòng)引用計(jì)數(shù),計(jì)數(shù)為0,則對(duì)象會(huì)被釋放)
- 大的紅色矩形可以描繪對(duì)象引用環(huán)的圖,這里如果是我們自己的東西,就能看出來哥哥對(duì)象的引用
- 如果這里沒有引用環(huán)的圖,首先我們找一下我們自定義的對(duì)象,正常完成任務(wù)這個(gè)對(duì)像就應(yīng)該釋放了,為了確認(rèn)這個(gè)對(duì)象有釋放,可以重寫dealloc方法,在此方法中l(wèi)og釋放信號(hào),看看是否被釋放
- 如果這里就是沒有釋放,我們可以點(diǎn)擊這里對(duì)象后的箭頭詳細(xì)查看下,這個(gè)對(duì)象的引用計(jì)數(shù)變化如圖
- All 代表所有的引用計(jì)數(shù)變化
- Unpaired表示那些未成對(duì)的變化·· (成對(duì)就是Leaks識(shí)別出了對(duì)應(yīng)的+1,-1)
- By Group會(huì)把相應(yīng)的變化分成一組
-
ByTime會(huì)按照順序列出引用計(jì)數(shù)變化
詳細(xì)信息.png
- 總結(jié):其實(shí)大多數(shù)問題在雙擊上文的代碼部分就可以解決了,少數(shù)問題需要詳細(xì)的分析ARC引用過程,
-
建議如果我們未發(fā)現(xiàn)表示內(nèi)存泄漏的紅x,但是我們想進(jìn)一步評(píng)估某個(gè)對(duì)象對(duì)于內(nèi)存的應(yīng)用,可以看看Allocations模版的折線圖,反復(fù)執(zhí)行從
創(chuàng)建對(duì)象 -> 銷毀對(duì)象這個(gè)過程,如果總占用內(nèi)存數(shù)會(huì)隨之增加,這說明這個(gè)對(duì)象沒有釋放,有些時(shí)候雖然占用的對(duì)象不是很嚴(yán)重,但是也會(huì)增加占用內(nèi)存,因此必須釋放這個(gè)對(duì)象 - 提示:有些情況下,對(duì)象沒有釋放是無法檢測(cè)到的,反復(fù)監(jiān)測(cè)內(nèi)存占用也沒有明顯的增加,這是最好在配置比較低的設(shè)備上測(cè)試一下。
文章學(xué)習(xí)路徑:關(guān)于Instruments-Leaks工具的歸納總結(jié)












