MRC:
1.為什么要進行內存管理?
iphone手機的內存是有限的,目前最大內存是2G,當運行頻繁多的app的時候,會占用大量的內存,當我們的app占用的內存大于40M的時候,ios系統會發出警告,當超過45M的時候系統會發出第二次警告,當占用內存超過120M的時候,app會閃退,所以我們需要對內存空間進行一個合理的管理,用以保證我們的app能夠流暢的運行;
2.什么是內存管理?
當我們編寫程序的時候,會聲明各種各樣的變量編寫各種各樣的代碼,他們都會占用內存,但是并不是所有的代碼和內存都是有我們進行釋放;
內存分為5個區域:棧、堆、bss段、數據段、代碼段;
棧:存放的是局部變量,當局部變量的作用域結束的時候就會由系統進行釋放局部變量所占用的內存空間;
堆:存放的是程序員手動申請的變量,手動申請的變量可以由程序員手動編寫代碼進行釋放;
bass段:存放的是為初始化的全局變量和靜態變量,當全局變量和靜態變量進行初始化的時候系統就會回收他們所占用的空間,然后把他們存放到數據段;
數據段:存放的是已經初始化了的全局變量和靜態變量和常量,當程序結束的時候由系統進行回收釋放;
代碼段:存放的是我們編寫的代碼,當程序結束的時候由系統進行回收釋放;
所以我們管理的其實只有堆空間。
3.如何進行內存管理?
在MRC機制下,每一個對象都有一個四個字節的存儲空間(一個整數),記錄對象被引用的數量,一個對象被創建出來以后,默認的引用計數為1,當一個對象引用計數為零的時候,對象會被立即回收,所以我們可以通過對引用計數的操作來進行對象的回收,并完成內存空間的操作;
4.引用計數是如何進行操作的?
我們可以向對象發送一些消息來操作對象的引用計數,發送retain消息可以添加一個引用計數,發送release消息可以減少一個引用計數,當一個對象的應用計數為零的時候他會被立即回收;
5.內存管理的原則:
A.當對象被創建出來以后,對象的引用計數默認是1,所以在這個對象使用完畢以后,我們應該為這個對象發送一條release消息,保證這個對象在使用完畢以后應用計數變為零,并且占用的內存空間被回收;
B. 當對象被別人使用的時候,別人就會為這個對象發送retain消息,表示使用的人多了一個,當別人不在使用對象的時候,別人就會為對象發送release消息,表示使用的人少了一個;
C. 當對象還有人正在使用的時候,對象就不應該被回收;
D.誰發送了retain消息,當使用完畢之后,誰要發送release消息;
ARC:
ARC是iOS 5推出的新功能,全稱叫 ARC(Automatic Reference Counting)。簡單地說,就是代碼中自動加入了retain/release,原先需要手動添加的用來處理內存管理的引用計數的代碼可以自動地由編譯器完成了。
簡單地理解ARC,就是通過指定的語法,讓編譯器(LLVM 3.0)在編譯代碼時,自動生成實例的引用計數管理部分代碼。有一點,ARC并不是GC,它只是一種代碼靜態分析(Static Analyzer)工具。
ARC主要提供了4種修飾符,他們分別是:__strong,__weak,__autoreleasing,__unsafe_unretained
__strong
表示引用為強引用。對應在定義property時的"strong"。所有對象只有當沒有任何一個強引用指向時,才會被釋放。
注意:如果在聲明引用時不加修飾符,那么引用將默認是強引用。當需要釋放強引用指向的對象時,需要將強引用置nil。
__weak
表示引用為弱引用。對應在定義property時用的"weak"。弱引用不會影響對象的釋放,即只要對象沒有任何強引用指向,即使有100個弱引用對象指向也沒用,該對象依然會被釋放。不過好在,對象在被釋放的同時,指向它的弱引用會自動被置nil,這個技術叫zeroing weak pointer。這樣有效得防止無效指針、野指針的產生。__weak一般用在delegate關系中防止循環引用或者用來修飾指向由Interface Builder編輯與生成的UI控件
__autoreleasing
表示在autorelease pool中自動釋放對象的引用,和MRC時代autorelease的用法相同。定義property時不能使用這個修飾符,任何一個對象的property都不應該是autorelease型的。
一個常見的誤解是,在ARC中沒有autorelease,因為這樣一個“自動釋放”看起來好像有點多余。這個誤解可能源自于將ARC的“自動”和autorelease“自動”的混淆。其實你只要看一下每個iOS App的main.m文件就能知道,autorelease不僅好好的存在著,并且變得更fashion了:不需要再手工被創建,也不需要再顯式得調用[drain]方法釋放內存池。
以下兩行代碼的意義是相同的。
NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC
NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC
__autoreleasing在ARC中主要用在參數傳遞返回值(out-parameters)和引用傳遞參數(pass-by-reference)的情況下。
比如常用的NSError的使用:
NSError *__autoreleasing error;
if (![data writeToFile:filename options:NSDataWritingAtomic error:&error])
{
NSLog(@"Error: %@", error);
}
注意,如果你的error定義為了strong型,那么,編譯器會幫你隱式地做如下事情,保證最終傳入函數的參數依然是個__autoreleasing類型的引用。
NSError *error; NSError *__autoreleasing tempError = error; // 編譯器NSError *error;
NSError *__autoreleasing tempError = error; // 編譯器添加
if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError])
{
error = tempError; // 編譯器添加
NSLog(@"Error: %@", error);
}
所以為了提高效率,避免這種情況,我們一般在定義error的時候將其(老老實實地=。=)聲明為__autoreleasing類型的:
NSError *__autoreleasing error;
在這里,加上__autoreleasing之后,相當于在MRC中對返回值error做了如下事情:
*error = [[[NSError alloc] init] autorelease];
error指向的對象在創建出來后,被放入到了autoreleasing pool中,等待使用結束后的自動釋放,函數外error的使用者并不需要關心error指向對象的釋放。
另外一點,在ARC中,所有這種指針的指針 (NSError **)的函數參數如果不加修飾符,編譯器會默認將他們認定為__autoreleasing類型。
比如下面的兩段代碼是等同的:
- (NSString *)doSomething:(NSNumber **)value
{
// do something
}
- (NSString *)doSomething:(NSNumber * __autoreleasing *)value
{
// do something
}
除非你顯式得給value聲明了__strong,否則value默認就是__autoreleasing的。
http://www.cnblogs.com/flyFreeZn/p/4264220.html 這篇文章比較詳細要多看