OC的內(nèi)存管理以及MRC與ARC
內(nèi)存中的五大區(qū)域:
棧區(qū),堆區(qū),BBS段,數(shù)據(jù)段和代碼段,其中除了堆區(qū)以外,其他區(qū)域的內(nèi)存管理由系統(tǒng)自行回收
OC對(duì)象是存儲(chǔ)在堆區(qū)的,所以O(shè)C的內(nèi)存管理主要是對(duì)”堆區(qū)中的OC對(duì)象”進(jìn)行管理
內(nèi)存管理中的幾個(gè)概念:
->引用計(jì)算器:既retainCount,每個(gè)OC對(duì)象內(nèi)部都有1個(gè)8字節(jié)空間用來存儲(chǔ)retainCount,表示有多少”人”正在使用;
對(duì)象剛被創(chuàng)建時(shí),默認(rèn)計(jì)數(shù)值就為1,當(dāng)計(jì)數(shù)值為0時(shí),系統(tǒng)會(huì)自動(dòng)調(diào)用dealloc方法將對(duì)象銷毀
引用計(jì)數(shù)器的用法:給對(duì)象發(fā)送相應(yīng)的技術(shù)操作來改變計(jì)數(shù)器的值
retain消息:使計(jì)數(shù)器+1
release消息:使計(jì)數(shù)器-1
retainCount消息:得到當(dāng)前當(dāng)前retainCount的值
->野指針:沒有初始化的指針變量
->僵尸對(duì)象:指一個(gè)對(duì)象已經(jīng)被回收,但其數(shù)據(jù)還存在內(nèi)存中
僵尸對(duì)象有可能可以訪問,也有可能不能訪問,取決于所占用空間是否已被重新分配.然而,對(duì)象一旦被回收就不該再被訪問,此時(shí)可以開啟僵尸對(duì)象檢測(cè),這樣系統(tǒng)會(huì)自動(dòng)檢查是否為僵尸對(duì)象,但同時(shí)也會(huì)降低執(zhí)行效率.
->內(nèi)存泄露:指對(duì)象沒有在該回收的時(shí)候被回收,而是一直駐留在內(nèi)存中,直到程序結(jié)束的時(shí)候才被釋放
內(nèi)存管理的分類:
->MRC:Manual Reference Counting,既手動(dòng)內(nèi)存管理
對(duì)引用計(jì)數(shù)器的操作全由程序員親自完成
->ARC:Automatic Reference Counting,既自動(dòng)內(nèi)存管理
(垃圾回收不能在iOS系統(tǒng)使用,故此處暫不討論)
系統(tǒng)會(huì)依照程序員的要求自動(dòng)改變引用計(jì)數(shù)器的值(Xcode6開始,默認(rèn)使用ARC)
手動(dòng)內(nèi)存管理:
->手動(dòng)內(nèi)存管理的原則:
1)一旦創(chuàng)建一個(gè)對(duì)象,這個(gè)對(duì)象的引用計(jì)數(shù)器的值就為1,所以必須要匹配1個(gè)release
2)只有在多1個(gè)人使用這個(gè)對(duì)象的時(shí)候才retain
只有在燒1個(gè)人使用這個(gè)對(duì)象的時(shí)候才release
3)retain的次數(shù)要和release次數(shù)相匹配
4)永遠(yuǎn)不要手動(dòng)調(diào)用對(duì)象的dealloc方法,而是讓系統(tǒng)自動(dòng)調(diào)用
->手動(dòng)內(nèi)存管理中內(nèi)存泄露的幾種情況:
1) retain和release不匹配送讲,retain多余release導(dǎo)致的內(nèi)存泄露;
2) 對(duì)象使用過程中潮瓶,沒有被release趴荸,而被賦值為nil;
3) 在方法中不當(dāng)?shù)氖褂昧藃etain;
手動(dòng)內(nèi)存管理的關(guān)鍵就是防止內(nèi)存泄露!!!!!防止內(nèi)存泄露要記住:
1) 誰創(chuàng)建”alloc","new",誰"release";
2) 誰”retain",誰"release";
->多對(duì)象的手動(dòng)內(nèi)存管理:
當(dāng)B類作為A類屬性時(shí),要防止內(nèi)存泄露,則A類的setter方法應(yīng)為:
其中setter方法實(shí)現(xiàn)還可寫成:
以上是標(biāo)準(zhǔn)的MRC內(nèi)存管理代碼.
->循環(huán)retain問題:
1) 遇到的問題:
當(dāng)兩個(gè)對(duì)象相互引用的時(shí)候.
A對(duì)象的屬性指向B對(duì)象, B對(duì)象的屬性指向A對(duì)象.
這個(gè)時(shí)候,如果兩邊都使用retain.就會(huì)出現(xiàn)內(nèi)存泄露. 都回收不了.
2) 解決方案:
1端使用retain,1端使用assign.(請(qǐng)查看@property帶參數(shù)用法的相關(guān)內(nèi)容)
需要注意的是: 使用assign的那1段,dealloc中不需要再去release這個(gè)對(duì)象了.
->自動(dòng)釋放池(autorelease)
1)原理:
存儲(chǔ)在自動(dòng)釋放池的對(duì)象,在自動(dòng)釋放池銷毀時(shí),會(huì)自動(dòng)調(diào)用該對(duì)象的release方法,故將對(duì)象存儲(chǔ)在自動(dòng)釋放池中,就不需要再寫release
2)創(chuàng)建方法:
@autorelease
{
} //大括弧表示自動(dòng)釋放池的范圍
3)將對(duì)象放入的方法:
在自動(dòng)釋放池的范圍中調(diào)用對(duì)象的autorelease方法.注:autorelease的返回值是對(duì)象本身,所以我們可以這樣創(chuàng)建對(duì)象:
@autorelease
{
類型 *對(duì)象 = [類名 alloc] init] autorelease];
}
4)使用注意:
a.只有在自動(dòng)釋放池中調(diào)用了對(duì)象的autorelease方法,這個(gè)對(duì)象才會(huì)被存儲(chǔ)到這個(gè)自動(dòng)釋放池之中
b. 對(duì)象的創(chuàng)建可以在自動(dòng)釋放池的外面,在自動(dòng)釋放池之中,調(diào)用對(duì)象的autorelease方法,就可以將這個(gè)對(duì)象存儲(chǔ)到這個(gè)自動(dòng)釋放池之中.
c. 當(dāng)自動(dòng)釋放池結(jié)束的時(shí)候.僅僅是對(duì)存儲(chǔ)在自動(dòng)釋放池中的對(duì)象發(fā)送1條release消息 而不是銷毀對(duì)象.
d. 如果在自動(dòng)釋放池中,調(diào)用同1個(gè)對(duì)象的autorelease方法多次.就會(huì)將對(duì)象存儲(chǔ)多次到自動(dòng)釋放池之中.在自動(dòng)釋放池結(jié)束的時(shí)候.會(huì)為對(duì)象發(fā)送多條release消息.那么這個(gè)時(shí)候就會(huì)出現(xiàn)僵尸對(duì)象錯(cuò)誤.
e. 自動(dòng)釋放池可以嵌套.調(diào)用對(duì)象的autorelease方法,會(huì)講對(duì)象加入到當(dāng)前自動(dòng)釋放池之中,只有在當(dāng)前自動(dòng)釋放池結(jié)束的時(shí)候才會(huì)像對(duì)象發(fā)送release消息.
5)使用規(guī)范:
我們一般情況下,寫1個(gè)類.會(huì)為我們的類寫1個(gè)同名的類方法,用來讓外界調(diào)用類方法來快速的得到1個(gè)對(duì)象.應(yīng)遵守規(guī)范:使用類方法創(chuàng)建的對(duì)象,要求這個(gè)對(duì)象在方法中就已經(jīng)被autorelease過了.這樣,我們只要在自動(dòng)釋放池中, 調(diào)用類方法來創(chuàng)建對(duì)象, 那么創(chuàng)建的對(duì)象就會(huì)被自動(dòng)的加入到自動(dòng)釋放中.
自動(dòng)內(nèi)存管理:
->自動(dòng)內(nèi)存管理原則: 編譯器會(huì)自動(dòng)的在合適的地方插入retain轿秧、release中跌、autorelase代碼;編譯器自動(dòng)為對(duì)象做引用計(jì)數(shù). 而作為開發(fā)者,完全不需要擔(dān)心編譯器會(huì)做錯(cuò)(除非開發(fā)者自己錯(cuò)用了ARC).
->強(qiáng)指針與弱指針:
強(qiáng)指針:默認(rèn)情況下,我們聲明的指針都為強(qiáng)指針,也可以使用__strong來顯示的聲明指針為強(qiáng)指針.
弱指針:使用__weak關(guān)鍵字修飾的指針,例如 __weak Person *p;
作用與區(qū)別:在ARC模式下,強(qiáng)指針與弱指針用來作為回收對(duì)象的標(biāo)準(zhǔn),當(dāng)1個(gè)對(duì)象即使用弱指針指向,但沒有任何強(qiáng)指針指向時(shí)就會(huì)被立即回收,此時(shí)該弱指針會(huì)被自動(dòng)設(shè)置為nil.
->ARC模式下的循環(huán)引用:
在ARC機(jī)制下,如果出現(xiàn)了循環(huán)引用,既A對(duì)象中有1個(gè)屬性是B對(duì)象. B對(duì)象中有1個(gè)屬性是A對(duì)象.此時(shí)如果兩邊都為strong.就會(huì)發(fā)生內(nèi)存泄露.
解決方案:1端使用strong 另外1端使用weak
MRC和ARC的轉(zhuǎn)換與兼容:
#? ARC兼容MRC的類
target --> Build Phaese? --->? Compiler Sources --> Compiler Flags
讓程序兼容ARC和非ARC部分。
轉(zhuǎn)變?yōu)榉茿RC? -fno-objc-arc
轉(zhuǎn)變?yōu)锳RC的, -f-objc-arc
#? MRC轉(zhuǎn)ARC
Xcode —> refactor? -->? Convert to Objective-C ARC? 選中要裝換的target -->? 調(diào)校代碼