版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、iOS 內(nèi)存暴增問題追查與使用陷阱原創(chuàng)作品, 允許轉(zhuǎn)載 , 轉(zhuǎn)載時請務(wù)必以超鏈接形式標(biāo)明文章原始出處 、作者信息和本聲明 。否則將追究法律責(zé)任 。iOS 平臺的內(nèi)存使用引用計數(shù)的機(jī)制,并且引入了半自動釋放機(jī)制;這種使用上的多樣性,導(dǎo)致 開發(fā)者在內(nèi)存使用上非常容易出現(xiàn)內(nèi)存泄 漏和內(nèi)存莫名的增長情況; 本文會介紹 iOS 平臺的 內(nèi)存使用原則與使用陷阱; 深度剖析 autorelease 機(jī)制;低內(nèi)存報警后的處理流程;并結(jié)合自身 實例介紹內(nèi)存暴增的問題追查記錄以及相關(guān)工具的使用情況;TAG內(nèi)存暴增,內(nèi)存泄漏, autorelease;內(nèi)存報警;iOS 平臺 內(nèi)存常見問題作為 iOS 平臺的開發(fā)者,
2、 是否曾經(jīng)為內(nèi)存問題而苦惱過?內(nèi)存莫名的持續(xù)增長, 程序莫名的 crash, 難以發(fā)現(xiàn)的內(nèi)存泄漏,這些都是 iOS 平臺內(nèi)存相關(guān)的常見問題;本文將會詳細(xì)介紹 iOS 平臺的 內(nèi)存管理機(jī)制, autorelease 機(jī)制和內(nèi)存 的使用陷阱,這些將會解決 iOS 平臺內(nèi)存上的大部分問 題,提高了程序的穩(wěn)定性;1 iOS 平臺內(nèi)存管理介 紹iOS 平臺的內(nèi)存管理采用引用計數(shù)的機(jī)制; 當(dāng)創(chuàng)建一個對象時使用 alloc 或者 allWithZone 方法時, 引用計數(shù)就會 +1;當(dāng)釋放對象使用 release 方法時,引用計數(shù)就是 -1; 這就意味著每一個對象都 會跟蹤有多少其他對象引用它,一旦引用計數(shù)
3、為0,該對象的內(nèi)存就會被釋放掉;另外,iOS 也提供了一種延時釋放的機(jī)制AutoRelease ,以這種方式申請的內(nèi)存,開發(fā)者無需手動釋放,系統(tǒng)會在某一時機(jī)釋放該內(nèi)存; 由于 iOS 平臺的這種內(nèi)存管理的多樣性,導(dǎo)致開發(fā)者在內(nèi)存使用上 很容易出現(xiàn)內(nèi)存泄漏或者程序莫名崩潰的情況,本文會詳細(xì)介紹 iOS 平臺內(nèi)存的使用規(guī)范與技 巧以及如何利用工具避免或者發(fā)現(xiàn)問題; 下圖是內(nèi)存從申請到釋放的一個完整示例:2 iOS 平臺內(nèi)存使用原 則2.1 對象的所有權(quán) 與銷 毀誰創(chuàng)建,誰釋放 ;如果是以 alloc , new 或者 copy , mutableCopy 創(chuàng)建的對象,則必須調(diào)用 release 或
4、者 autorelease 方法釋放內(nèi)存;如果沒有釋放,則導(dǎo)致內(nèi)存泄漏!誰 retain ,誰釋放 ;如果對一個對象發(fā)送 retain 消息,其引用計數(shù)會 +1 ,則使用完必須發(fā)送 release 或者 autorelease 方法釋放內(nèi)存或恢復(fù)引用計數(shù);如果沒有釋放,則導(dǎo)致內(nèi)存泄漏!沒創(chuàng)建且沒 retain ,別釋放 ;不要釋放那些不是自己 alloc 或者 retain 的對象, 否則程序會 crash ;不要釋放 autorelease 的對象, 否則程序會 crash ;對象的深拷貝與淺拷 貝一般來說, 復(fù)制一個對象包括創(chuàng)建一個新的實例, 并以原始對象中的值初始化這個新的實例。 復(fù) 制
5、非指針型實例變量的值很簡單, 比如布爾, 整數(shù)和浮點數(shù)。 復(fù)制指 針型實例變量有兩種方法。 一種方法稱為淺拷貝, 即將原始對象的指針值復(fù)制到副本中。 因此, 原始對象和副本共享引用數(shù) 據(jù)。另一種方法稱為深拷貝,即復(fù)制指針 所引用的數(shù)據(jù),并將其賦給副本的實例變量。深拷貝深拷貝的流程是 先創(chuàng)建一個 新 的對象且引用計數(shù)為 1,并用舊對象的值初始化這個新對象;ClassA* objA = ClassA alloc init;ClassA* objB = objA copy ;objB 是一個新對象,引用計數(shù)為 1 ,且 objB 的數(shù)據(jù)等同 objA 的數(shù)據(jù);注意: objB 需要釋放,否則會引起內(nèi)
6、存泄漏!淺拷貝淺拷貝的流程是,無需引入新的對象,把原有對象的引用計數(shù) +1 即可ClassA* objA = ClassA alloc init;ClassA* objB = objA retain ;注意: objB 需要釋放,恢復(fù) objA 的引用計數(shù),否則會引起內(nèi)存泄漏!2.3對象的存取方 法屬性 聲明和實 現(xiàn)變量聲明的常用屬性類型包括 readonly ,assign,retain 和 copy ;且系統(tǒng)會 自動 為聲明了屬性的變 量生成 set和 get 函數(shù);readonly 屬性: 只能讀,不能寫;assign 屬性: 是默認(rèn)屬性,直接賦值,沒有任何保留與釋放問題;retain
7、屬性: 會增加原有對象的引用計數(shù)并且在賦值前會釋放原有對象,然后在進(jìn)行賦值;copy 屬性: 會復(fù)制原有對象,并在賦值前釋放原有對象,然后在進(jìn)行賦值;使用屬性聲明可能帶來的隱 患當(dāng)一個非指針變量使用 retain(或者 copy)這個屬性時,盡量不要顯性的release 這個變量; 直接給這個變量置空即可;否則容易產(chǎn)生過度釋放,導(dǎo)致程序 crash; 例如:ClassA 類的 strName 是 NSString* 類型的變量且聲明的屬性為 retain ;ClassA.strName = nil; /* 釋放原有對象且對此對象賦值為空 */ClassA.strName release; /*
8、 strName 內(nèi)存可能已經(jīng)被釋放過了, 將導(dǎo)致程序 crash */Assign 這個屬性一般是非指針變量(布爾類型,整形等)時用這個類型;屬于直接賦值型,不 需要考慮內(nèi)存的保留與釋放;如果一個指針類型的變量使用 assign 類型的屬性, 有可能引用已經(jīng)釋放的變量; 導(dǎo)致程序 crash ; 例如:ClassB* obj =ClassB alloc init autorelease ;ClassA.strName = obj; /* strName 指向 obj 的內(nèi)存地址 */ 后續(xù)在使用 ClassA.strName 的時候, 因為 obj 是 autorelease的,可能 obj
9、 的內(nèi)存已經(jīng)被回收; 導(dǎo)致引用無效內(nèi)存,程序 crash;3iOS平臺AutoRelease 機(jī)制自動釋放池的常見問題大家在開發(fā) iOS 程序的時候,是否遇到過在列表滑動的情況內(nèi)存莫名的增長,頻繁訪問圖片的 時候內(nèi)存莫名的增長,頻繁的打開和關(guān)閉數(shù)據(jù)庫的時候內(nèi)存莫名的增長 這些都是拜 iOS 的 autorelease機(jī)制所賜;具體分析如下:1: 滑動列表的時候,內(nèi)存出現(xiàn)莫名的增長,原因可能有如下可能:1:沒有使用 UITableView 的 reuse機(jī)制;導(dǎo)致每顯示一個 cell 都用 autorelease的方式重新 alloc 一次; 導(dǎo)致 cell 的內(nèi)存不斷的增加 ;2:每個 cel
10、l 會顯示一個單獨的 UIView ,在 UIView 發(fā)生內(nèi)存泄漏,導(dǎo)致 cell 的內(nèi)存不斷增長 ;2: 頻繁訪問圖片的時候,內(nèi)存莫名的增長;頻繁的訪問網(wǎng)絡(luò)圖片, 導(dǎo)致 iOS 內(nèi)部 API ,會不斷的分配 autorelease方式的 buffer 來處理圖片的 解碼與顯示; 利用圖片 cache可以緩解一下此問題;3: 頻繁打開和關(guān)閉 SQLite ,導(dǎo)致內(nèi)存不斷的增長;在進(jìn)行 SQLite 頻繁打開和關(guān)閉操作, 而且讀寫的數(shù)據(jù) buffer 較大,那么 SQLite 在每次打開與關(guān) 閉的時候,都會利用 autorelease的方式分配 51K 的內(nèi)存; 如果訪問次數(shù)很多,內(nèi)存馬上就會
11、頂 到幾十兆,甚至上百兆!所以針對頻繁的讀寫數(shù)據(jù)庫且數(shù)據(jù) buffer 較大的情況,可以設(shè)置 SQLite 的長連接方式;避免頻繁的打開和關(guān)閉數(shù)據(jù)庫 ;自動釋放池的概念NSAutoreleasePool 內(nèi)部包含一個數(shù)組( NSMutableArray ),用來保存聲名為 autorelease的所有 對象。如果一個對象聲明為autorelease,系統(tǒng)所做的工作就是把這個對象加入到這個數(shù)組中去。ClassA *obj1 = ClassA alloc init autorelease; /retain count = 1,把此對象加入 autorelease pool中NSAutoreleas
12、ePool 自身在銷毀的時候,會遍歷一遍這個數(shù)組, release數(shù)組中的每個成員。如果此時數(shù)組中成員的 retain count 為 1,那么 release 之后, retain count 為 0,對象正式被銷毀。如果此時數(shù)組中成員的 retain count 大于 1,那么 release 之后, retain count 大于 0,此對象依然沒 有被銷毀,內(nèi)存泄露。自動釋放池的作用域與嵌 套AutoreleasePool 是可以嵌套使用的! 池是被嵌套的,嵌套的結(jié)果是個棧,同一線程只有當(dāng)前棧頂 pool 實例是可用的:當(dāng)短生命周期內(nèi), 比如一個循環(huán)中, 會產(chǎn)生大量的臨時內(nèi)存, 可以創(chuàng)
13、建一個臨時的 autorelease pool , 這樣可以達(dá)到快速回收內(nèi)存的目的;自動施放池的手動創(chuàng)建與自動創(chuàng) 建需要 手動創(chuàng)建自動釋放 池如果你正在編寫一個不是基于 ApplicationKit 的程序 ,比如命令行工具 ,則沒有對自動釋放池的內(nèi)置支持 ;你必須自己創(chuàng)建它們 。如果你生成了一個從屬線程 ,則一旦該線程開始執(zhí)行 ,你必須立即創(chuàng)建你自己的自動釋放池 否則 ,你將會泄漏對象 。如果你編寫了一個循環(huán) ,其中創(chuàng)建了許多臨時對象 ,你可以在循環(huán)內(nèi)部創(chuàng)建一個自動釋放池 以便在下次迭代之前銷毀這些對象 。這可以幫助減少應(yīng)用程序的最大內(nèi)存占用量 。 比如鼠標(biāo)按下事件 自動創(chuàng)建一系統(tǒng) 自動創(chuàng)建
14、自動釋放池Application Kit 會在一個事件周期(或事件循環(huán)迭代)的開端 個自動釋放池,并且在事件周期的結(jié)尾釋放它 .iOS 平臺內(nèi)存使用陷阱重復(fù) 釋放 在前文已經(jīng)提到,不要釋放不是自己創(chuàng)建的對象; 釋放自己的 autorelease 對象, app 會 crash; 釋放系統(tǒng)的 autorelease 對象, app 會 crash;循環(huán)引用循環(huán)引用,容易產(chǎn)生野引用,內(nèi)存無法回收,最終導(dǎo)致內(nèi)存泄漏!可以通過弱引用的方式來打破 循環(huán)引用鏈;所謂的弱引用就是不需要retain ,直接賦值的方式,這樣的話,可以避免循環(huán)引用的問題,但是需要注意的是,避免重復(fù)釋放的問題;iOS 平臺內(nèi)存報警
15、機(jī)制由于 iOS 平臺的內(nèi)存管理機(jī)制, 不支持虛擬內(nèi)存, 所以在內(nèi)存不足的情況, 不會去 Ram 上創(chuàng) 建 虛擬內(nèi)存; 所以一旦出現(xiàn)內(nèi)存不足的情況, iOS 平臺會通知所有已經(jīng)運行的 app,不論是前臺 app 還是后臺掛起的 app,都會收到 memory warning 的notice ;一旦 app收到 memory warning 的notice , 就應(yīng)該回收占用內(nèi)存較大的變量;5.1 內(nèi)存報警處理流 程1: app收到系統(tǒng)發(fā)過來的 memory warning 的 notice ;2: app 釋放占用較大的內(nèi)存;3: 系統(tǒng)回收此 app 所創(chuàng)建的 autorelease 的對象;
16、4: app 返回到已經(jīng)打開的頁面時,系統(tǒng)重新調(diào)用viewdidload 方法, view 重新加載頁面數(shù)據(jù);重新顯示;內(nèi)存報警測試方法在 Simulate 上可以模擬低內(nèi)存報警消息;iOS 模擬器 - 硬件 - 模擬內(nèi)存警告;開發(fā)者可以在模擬器上來模擬手機(jī)上的低內(nèi)存報警情況,可以避免由于低內(nèi)存報警引出的 app 的莫名 crash 問題;iOS 平臺內(nèi)存檢查工 具6.1 編譯和分析工具 AnalyzeiOS 的分析工具可以發(fā)現(xiàn)編譯中的 warning ,內(nèi)存泄漏隱患,甚至還可以檢查出 logic 上的問題; 所以在自測階段一定要解決 Analyze 發(fā)現(xiàn)的問題,可以避免出現(xiàn)嚴(yán)重的bug;內(nèi)存
17、泄漏隱患提示 :Potential Leak of an object allocated on line數(shù)據(jù)賦值隱患提示 :The left operand of is a garbage value;對象引用隱患提示 :Reference-Counted object is used after it is released;以上提示均比較嚴(yán)重,可能會引起嚴(yán)重問題,需要開發(fā)者密切關(guān)注!內(nèi)存檢測工具內(nèi)存泄漏檢測工具 LeakLeak 工具可以很容易的統(tǒng)計所有內(nèi)存泄漏的點, 而且還可以顯示在那個文件, 哪行代碼有內(nèi) 存 泄漏,這樣定位問題比較容易,也比較方面;但是 Leak 在統(tǒng)計內(nèi)存泄漏的時候會把 autorelease 方式的內(nèi)存也統(tǒng)計進(jìn)來; 所以我們在查找內(nèi)存泄漏情況的時候, 可以 autorelease 的情況忽略掉;Leak 工具:通過 Leak 工具可以很快發(fā)現(xiàn)代碼中的內(nèi)存泄漏,通過工具也可以很快找到發(fā)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年海南開放大學(xué)馬克思主義基本原理概論期末考試題含答案解析(奪冠)
- 2025年浙江省湖州市單招職業(yè)適應(yīng)性測試題庫附答案解析
- 2024年滇西應(yīng)用技術(shù)大學(xué)馬克思主義基本原理概論期末考試題附答案解析(奪冠)
- 2026國家稅務(wù)總局重慶市稅務(wù)局事業(yè)單位招聘40人備考題庫(含答案詳解)
- 2025年于都縣招教考試備考題庫帶答案解析(必刷)
- 2025年廣豐縣招教考試備考題庫帶答案解析(奪冠)
- 2025年萬安縣招教考試備考題庫及答案解析(必刷)
- 2024年甘肅警察學(xué)院馬克思主義基本原理概論期末考試題帶答案解析
- 2024年賀蘭縣幼兒園教師招教考試備考題庫帶答案解析(必刷)
- 2025年灌南縣幼兒園教師招教考試備考題庫附答案解析
- 2025年秋季散學(xué)典禮校長講話:以四馬精神赴新程攜溫暖期許啟寒假
- 2026貴州省黔晟國有資產(chǎn)經(jīng)營有限責(zé)任公司面向社會招聘中層管理人員2人備考考試試題及答案解析
- 2025年營養(yǎng)師考試練習(xí)題及答案
- 2026中國電信四川公用信息產(chǎn)業(yè)有限責(zé)任公司社會成熟人才招聘備考題庫及答案詳解一套
- 通信工程冬季施工安全培訓(xùn)
- 中醫(yī)外科乳房疾病診療規(guī)范診療指南2023版
- 壓實瀝青混合料密度 表干法 自動計算
- 田口三次設(shè)計
- 《我的戒煙》閱讀答案
- GB/T 7442-2007角向磨光機(jī)
- GB/T 324-2008焊縫符號表示法
評論
0/150
提交評論