MRC下的內(nèi)存管理
內(nèi)存中的5大區(qū)域
- 棧區(qū)
這個(gè)區(qū)的內(nèi)存保存的是局部變量, 當(dāng)作用域結(jié)束后, 系統(tǒng)就會(huì)自動(dòng)回收內(nèi)存.
局部變量num4 = 0x7fff5fbff7bc
- 堆區(qū)
這個(gè)區(qū)是用來(lái)程序員通過(guò)代碼來(lái)申請(qǐng)的空間, 這塊空間會(huì)一直保存到程序的結(jié)束, 直到程序員手動(dòng)來(lái)釋放. 內(nèi)存管理只會(huì)管理堆區(qū)上的內(nèi)存.
對(duì)象小明在堆區(qū)的地址是:0x100400200
- BSS段
這個(gè)區(qū)的內(nèi)存主要是用來(lái)保存未被初始化的全局變量或靜態(tài)變量, 一旦被初始化后就會(huì)將數(shù)據(jù)轉(zhuǎn)移到數(shù)據(jù)段.同樣是系統(tǒng)自動(dòng)執(zhí)行的.
- 數(shù)據(jù)段
這個(gè)區(qū)的內(nèi)存是用來(lái)保存全局變量或靜態(tài)變量, 直到程序結(jié)束才會(huì)被系統(tǒng)自動(dòng)回收.
全局變量num1 = 0x1000011f0
靜態(tài)變量num3 = 0x1000011f4
類地址p1 = 0x1000011c8
- 代碼區(qū)
這個(gè)區(qū)的內(nèi)存是用來(lái)存儲(chǔ)程序中的代碼.
函數(shù)指針 p = 0x100000dd0
內(nèi)存管理的必要性
內(nèi)存中的對(duì)象如果不在不用的時(shí)候及時(shí)的回收, 可以想象對(duì)于有限的內(nèi)存來(lái)說(shuō)是不可能實(shí)現(xiàn)的.
例如:iPhone的內(nèi)存警告機(jī)制, 內(nèi)存到40M就會(huì)警告, 如果到了120M就會(huì)閃退.
怎么進(jìn)行內(nèi)存管理
1.相關(guān)概念
如果想對(duì)內(nèi)存進(jìn)行管理, 首先必須理解與內(nèi)存管理相關(guān)的概念.
- 僵尸對(duì)象與野指針
僵尸對(duì)象: 指的是內(nèi)存中的對(duì)象已經(jīng)被釋放, 但還沒(méi)有被CPU給分配出去.
野指針: C語(yǔ)言中的野指針指的是定義了一個(gè)指針但是沒(méi)有初始化, 導(dǎo)致指針中存儲(chǔ)的是垃圾值, 指向內(nèi)存中的任意地址.
OC中的野指針指的是指針指向的對(duì)象已經(jīng)被回收了, 如果仍有指針指向容易誤操作.
- 內(nèi)存泄漏
內(nèi)存泄漏: 指的是一個(gè)應(yīng)該被回收的對(duì)象, 沒(méi)有得到及時(shí)的回收. 這樣的對(duì)象會(huì)一直存在于內(nèi)存中 直到程序結(jié)束. 這樣的結(jié)果會(huì)導(dǎo)致內(nèi)存的泄漏.
- MRC與ARC
MRC: Manual Reference Counting, 指的是Xcode下編寫代碼需要手動(dòng)對(duì)內(nèi)存進(jìn)行管理.
ARC: Automatic Reference Counting, 指的是Xcode下編寫代碼系統(tǒng)會(huì)自動(dòng)的進(jìn)行內(nèi)存管理.
- 引用計(jì)數(shù)器
引用計(jì)數(shù)器: 所有的OC對(duì)象內(nèi)都有一個(gè)叫做retainCount的屬性, 這個(gè)屬性的默認(rèn)值是1, unsigned long類型.
- dealloc方法
dealloc方法: 所有的OC對(duì)象在被回收之前都會(huì)系統(tǒng)自動(dòng)調(diào)用dealloc方法
2.內(nèi)存管理
- 引用計(jì)數(shù)器的使用
引用計(jì)數(shù)器的默認(rèn)值是1, 調(diào)用類的retain方法使引用計(jì)數(shù)器+1, 調(diào)用類的release方法引用計(jì)數(shù)器-1. 當(dāng)引用計(jì)數(shù)器為0時(shí), 對(duì)象就會(huì)被回收.
- (instancetype)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- 野指針與僵尸對(duì)象
為了避免野指針指向僵尸對(duì)象造成誤操作, 建議將在指針變成野指針后賦值為nil. 在Xcode下也可以打開(kāi)僵尸對(duì)象檢查, 但是這樣會(huì)很影響程序的性能, 謹(jǐn)慎使用.
- 內(nèi)存管理原則
- 有對(duì)象的創(chuàng)建就要匹配release.
Person *p1 = [Person new];
[p1 release];
- retain的次數(shù)要和release匹配.
Person *p1 = [Person new];
[p1 retain];
[p1 retain];
[p1 release];
[p1 release];
[p1 release];
- 為了代碼的規(guī)整, 誰(shuí)用了一個(gè)對(duì)象誰(shuí)就retain, 誰(shuí)不用誰(shuí)就release, 誰(shuí)負(fù)責(zé)retain, 誰(shuí)就負(fù)責(zé)release.
- 不要隨便retain, 多一個(gè)人使用的時(shí)候才retain, 少一個(gè)人使用的話就release.
- 單個(gè)對(duì)象內(nèi)存管理
1. 有對(duì)象的創(chuàng)建 就必須要匹配1個(gè)release.
2. retain次數(shù)和release次數(shù)一定要匹配.
3. 只有在指針?lè)Q為野指針的時(shí)候才賦值為nil
4. 在方法中不要隨意的為傳入的對(duì)象retain.
- 多個(gè)對(duì)象內(nèi)存管理
1.當(dāng)一個(gè)對(duì)象是另一個(gè)對(duì)象的參數(shù)時(shí)候, 重寫setter方法和dealloc方法
2.對(duì)象作為參數(shù)需要將舊的對(duì)象release, 新的對(duì)象retain
3.同一個(gè)對(duì)象作為參數(shù)被賦值了兩次時(shí)會(huì)造成內(nèi)存泄漏, 所以重構(gòu)setter方法的時(shí)候一定要加入if判斷新舊對(duì)象是否為同一個(gè)對(duì)象
重寫setter和dealloc的標(biāo)準(zhǔn)寫法
- (void)setCar:(Car *)car
{
if(_car != car)
{
[_car release];
_car = [car retain];
}
}
- (void)dealloc
{
[_car release];
[super dealloc];
}
- @property參數(shù)
MRC下:
a: 多線程相關(guān)
atomic: (默認(rèn)值)setter方法加了一把線程安全鎖, 效率低
nonatomic: 建議使用
b: 與生成setter方法的實(shí)現(xiàn)相關(guān)
assign: (默認(rèn)值) 生成的setter方法的實(shí)現(xiàn)就是直接賦值
retain: 生成的setter就是標(biāo)準(zhǔn)的MRC內(nèi)存管理管理代碼.ps:dealloc內(nèi)的release代碼還需要一樣寫
c: 與生成只讀, 讀寫屬性的相關(guān)
readwrite: (默認(rèn)值)代表同時(shí)生成getter和setter
readonly: 只生成getter, 不會(huì)生成setter
d: 與生成的getter, setter方法相關(guān)
getter=XXX: 重寫getter的方法名
setter=ooo: : 重寫setter方法的名字
在BOOL類型的參數(shù)中重寫getter
- 類的循環(huán)引用
例如:Person類中有個(gè)Book類屬性, 而B(niǎo)ook類中又有一個(gè)作者(Person)屬性. 這樣在導(dǎo)入頭文件的時(shí)候就會(huì)出現(xiàn)循環(huán)引用.
解決辦法:
其中一邊不要使用#import引入對(duì)方的頭文件.
而是使用@class 類名. 這樣就可以不引用對(duì)方頭文件的情況下, 告訴編譯器這是一個(gè)類.
@class
作用及含義: 相當(dāng)于向編譯器聲明了一個(gè)類, 并沒(méi)有實(shí)現(xiàn)它.(參考c語(yǔ)言的函數(shù)的聲明)
- 對(duì)象間的相互引用
例如:Person類的小明對(duì)象有本書(shū)<三國(guó)>(Book類), <三國(guó)>對(duì)象有一個(gè)作者屬性是小明(Person類), 這個(gè)時(shí)候就出現(xiàn)了循環(huán)引用.
解決方法:
1端使用retain, 一端使用assign , assign那一邊就不需要release.
ARC下的內(nèi)存管理
ARC概述
Automatic Reference Couunting, 顧名思義是系統(tǒng)會(huì)自動(dòng)幫助我們?nèi)ビ?jì)算引用計(jì)數(shù)器的值, 是WWDC2011和iOS5引入的最大的變革和最激動(dòng)人心的變化.ARC是新的LLVM3.0編譯器的一項(xiàng)特性,使用ARC,可以說(shuō)一舉解決了廣大iOS開(kāi)著所憎恨的手動(dòng)管理內(nèi)存的麻煩.
ARC管理內(nèi)存的原理
- 強(qiáng)指針與弱指針
默認(rèn)情況下, 我們聲明的指針就是強(qiáng)指針, 或者使用__strong來(lái)顯示的聲明一個(gè)強(qiáng)類型的指針.
弱指針指的是用__weak修飾的指針, 無(wú)論強(qiáng)指針還是弱指針, 作為存儲(chǔ)對(duì)象的地址, 并且通過(guò)指針操作對(duì)象方面上沒(méi)有任何區(qū)別, 唯一的區(qū)別是在對(duì)象回收上, 如果沒(méi)有任何強(qiáng)類型的指針指向的時(shí)候, 對(duì)象就會(huì)回收.
新建一個(gè)項(xiàng)目的話系統(tǒng)會(huì)默認(rèn)開(kāi)啟ARC, 使用ARC的過(guò)程中, 系統(tǒng)會(huì)在編譯的過(guò)程中自動(dòng)的在合適的位置為我們加上
retain, release, autorelease. 對(duì)象會(huì)在沒(méi)有強(qiáng)類型的指針指向的時(shí)候被回收掉, 其本質(zhì)還是對(duì)象的引用計(jì)數(shù)器被減為0了.
ARC與MRC的轉(zhuǎn)換和兼容
ARC和MRC通過(guò)命令-fno-objc-arc可以相互兼容, 通過(guò)Xcode可以將MRC手動(dòng)轉(zhuǎn)成ARC, 由于系統(tǒng)的處理過(guò)于簡(jiǎn)單, 謹(jǐn)慎使用.
ARC與垃圾回收機(jī)制的區(qū)別
垃圾回收機(jī)制GC是在程序的運(yùn)行期間不斷循環(huán)掃描對(duì)象是否無(wú)人使用, 如果沒(méi)有使用就回收.
ARC是在程序編譯的過(guò)程就系統(tǒng)自動(dòng)的加上了一些內(nèi)存管理代碼.