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