內存管理就是確保開辟的堆空間被正確的釋放。如果堆空間沒有釋放,稱為【內存泄露】使用已經釋放的空間,稱為【提前釋放】重復釋放同一個空間,稱為【重復釋放】
(1)當我們要釋放一個堆,首先要確定使用這個堆的指針,都訪問完畢。避免提前釋放。
(2)釋放指針指向的堆空間,首先要確定哪些指針指向同一個堆,這些指針,只能釋放一個。避免重復釋放。
(3)模塊化操作,哪個模塊負責釋放,將成為巨大的難題。
(4)多線程操作,無法確定哪個線程最后使用完畢。
【結論】OC的內存管理,就是在編寫程序時,保證計數器的數值和使用對象指針數相同,保證計數的增加和減少次數相同。?
【手動內存管理MRC】
一.關閉ARC
//工程 —> Targets —> BuildSetting —> 搜索【gar】
【YES】—>【NO】
NSObject:
- (id)retain;//引用計數加1
- (void)release;//引用計數減1 理論上減到0釋放,原則上一個指針只能發送該消息一次
- (NSUInteger)retainCount;
//返回對象的當前引用計數
Δ二.內存管理的法則
1.凡是用alloc,retain,new(或使用new開頭的方法),copy(或使用copy開頭的方法),mutableCopy(或使用mutableCopy開頭的方法)【創建】的對象,都必須使用release或autorelease方法【釋放】
Δ2.誰創建誰釋放(哪個類創建,哪個類釋放;誰寫alloc,誰寫release)。
【注意事項】
1.對象的成員變量在構造方法中創建,應在析構方法中釋放。
2.注意指針的轉移 釋放舊對象 保留新對象。
3.從數據結構如數組中取出對象地址,如果需要長時間使用,應當retain。
【相關方法】
copy 和 mutableCopy:只用來復制字符串
new
[Dog new] <==> [[Dog alloc] init];
三.自動釋放池
@autoreleasepool{
@autoreleasepool{
}
}
NSAutoreleasePool
//自動釋放池原本也是對象,為了配合ARC改成了關鍵字。
- (id)autorelease;
//自動釋放/ 延遲釋放
【注】自動釋放池類似一個數組,進行延遲釋放,不會馬上計數器減1,而是將當前對象,放入最近的自動釋放池。當池釋放時,將每個池中的元素釋放一次。
【注】在iOS程序中,每個觸發周期,都會創建并銷毀一個自動釋放池。
【自動釋放原則】
1.方法的局部變量可以使用自動釋放。
2.非用自動釋放不可的情況
【結論】只有一個函數中使用的對象,可以使用類方法創建。
四.相關工具
PRoduct —> profile —> leaks
【自動內存管理ARC】
//從Xcode5以后,默認自動內存管理
automatic reference counting;
//自動引用計數
【提】簡單點說就是讓編譯器完成堆空間的引用計數加減,自動釋放。程序員不再寫 retain release等方法
【另】OC的自動內存管理,不同于java垃圾回收。而是在預處理時,直接在應該保留的地方,添加retain,在應該釋放的地方,添加release。是直接添加代碼。
【另】從效率上,ARC優于手動內存管理。
一.ARC的局限
1.使用ARC,可能因為代碼的不規范,導致內存提前釋放。
//尤其使用AVAudioplayer類的時候,很可能造成提前釋放。
2.導入一些第三方庫,或者導入舊代碼,這些代碼不支持ARC。
二.解決ARC的局限
1.將不使用ARC的代碼轉成ARC代碼
Edit —> Refactor —> Convert to ARC
2.ARC非ARC混編
//同一個工程中,部分文件使用ARC,部分文件不使用ARC。
Build phase -----> Complie Source
-fno-objc-arc
三.使用ARC的技巧
1.四個關鍵字 修飾引用
__strong(強引用) 缺省屬性,其修飾的對象指針,指向哪個對象,會對該對象retain,離開哪個對象,會對該對象release。
__weak(弱引用)其修飾的對象指針,指向任何對象都不會retain。這樣的指針指向的對象隨時可能消失。如果對象消失了,這個指針會自動變成nil。
//在iOS編程中,代理對象使用弱引用。
__unsafe_unretained 其修飾的對象指針,指向任何對象都不retain。當指向的對象消失,該指針不會變成nil,仍然指向已經釋放的對象
__autoreleasing 只用來修飾需要被傳入地址的指針。如:
__autoreleasing NSError * error; &error;
2.屬性的()參數,原則上,不能寫retain copy了,只能寫Strong,如果不想retain,寫Weak
【注】但實際上ARC對這方面很寬松,謝了retain也沒關系。
3.id 指向對象,不能用void * p指向對象。
int a;
void * p = &a;
id p = [[NSObject alloc] init];
4.C的結構體中,不能聲明對象指針。否則這個指針不會進行內存管理
struct sct{
id obj;
};
5.不能(顯式)手動調用父類的dealloc
-(void)dealloc
{
self.name = nil;
//自動調用父類的dealloc
}
新聞熱點
疑難解答