內(nèi)存管理是任何編程語言中最重要的過程之一。它是一個過程,通過該對象的內(nèi)存時,需要時分配,當不再需要時釋放。
管理對象的內(nèi)存性能是一個問題,如果一個應用程序沒有免費的不需要的對象,其內(nèi)存占用量的增長和性能將受到影響。
Objective-C的內(nèi)存管理技術(shù)大致可分為兩類。
“手動保留釋放”或MRR
“自動引用計數(shù)”或ARC
在 MRR中,我們明確地管理內(nèi)存,在我們自己的跟蹤對象。這是使用一種模式,被稱為引用計數(shù),基礎類NSObject 提供配合運行環(huán)境。
MRR 和 ARC 之間的唯一區(qū)別是,保留和釋放處理前手動而隨后自動處理。
下圖表示如何在Objective-C 內(nèi)存管理工作的一個例子。
在上圖中所示的A類對象的存儲生命周期。正如可以看到,如下圖所示的對象保留計數(shù),當保留計數(shù)的對象變?yōu)?的,對象是完全釋放,其它對象使用的內(nèi)存被釋放。
A類對象第一次被創(chuàng)建,使用分配/ NSObject的init方法?,F(xiàn)在,保留計數(shù)變?yōu)?。
現(xiàn)在,B類保留A類的對象和保留計數(shù)類A的對象變成2。
然后,C類對象的一個副本?,F(xiàn)在,它被創(chuàng)建為A類的實例變量的值相同的另一個實例。在這里,保留計數(shù)為1,而不是原來的對象的保留計數(shù)。這在圖中由虛線表示。
復制的對象將釋放C類使用釋放方法,并保留計數(shù)變?yōu)?,因此對象被銷毀。
在初始A類對象的情況下,保留計數(shù)為2,它有兩次被釋放,以便將其銷毀。這是通過類A和B類保留計數(shù)遞減為1和0,分別使用 release 語句。最后,對象將被破壞。
我們擁有我們所創(chuàng)建的任何對象:我們創(chuàng)建了一個對象,使用方法的名字以 "alloc", "new", "copy" 或 "mutableCopy"開始
我們可以把一個對象使用保留所有權(quán):接收到的對象通常是保證在收到它的方法仍然有效,并且該方法也可以安全地返回其調(diào)用對象。我們使用保留在兩種情況下:
在執(zhí)行存取方法或者一個init方法,采取所有權(quán),我們要存儲一個對象的屬性值。
為了防止一個對象被無效的一些其他的操作的一個副作用。
當我們不再需要它,我們必須放棄所有權(quán)的對象,我們自己:我們放棄對象的所有權(quán),通過發(fā)送一個釋放消息或一個自動釋放的消息。在可可術(shù)語,放棄一個對象的所有權(quán),因此通常被稱為“釋放”一個對象。
不能放棄擁有一個對象(不屬于自己):這只是推論明確說明以前的策略規(guī)則。
#import <Foundation/Foundation.h> @interface SampleClass:NSObject - (void)sampleMethod; @end @implementation SampleClass - (void)sampleMethod { NSLog(@"Hello, World! "); } - (void)dealloc { NSLog(@"Object deallocated"); [super dealloc]; } @end int main() { /* my first program in Objective-C */ SampleClass *sampleClass = [[SampleClass alloc]init]; [sampleClass sampleMethod]; NSLog(@"Retain Count after initial allocation: %d", [sampleClass retainCount]); [sampleClass retain]; NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]); [sampleClass release]; NSLog(@"Retain Count after release: %d", [sampleClass retainCount]); [sampleClass release]; NSLog(@"SampleClass dealloc will be called before this"); // Should set the object to nil sampleClass = nil; return 0; }
當我們編譯上面的程序,我們會得到下面的輸出。
2013-09-28 04:39:52.310 demo[8385] Hello, World! 2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1 2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2 2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1 2013-09-28 04:39:52.311 demo[8385] Object deallocated 2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
在自動引用計數(shù)或ARC時,系統(tǒng)使用相同的引用計數(shù)系統(tǒng)MRR,但它插入相應的內(nèi)存管理方法要求我們在編譯時間。我們強烈鼓勵使用ARC新的項目中。如果我們使用ARC,通常是有沒有需要了解本文檔中描述的底層實現(xiàn),盡管它可能在某些情況下是有益的。如需更多關(guān)于ARC,請參閱 過渡到ARC發(fā)布注釋.
正如上面所提到的,在ARC中我們需要不加釋放和保留的方法,因為這將得到編譯器的處理。事實上,底層的 Objective-C 程序仍然是一樣的。它使用的保留和釋放內(nèi)部的操作使它更容易為開發(fā)人員代碼不擔心這些操作的情況下,這將減少代碼編寫量和內(nèi)存泄漏的可能性。
還有另一個稱為垃圾收集的原則,這是用來在Mac OS-X以及MRR,但其在OS-XMountain Lion 中棄用以來,它已經(jīng)不隨著MRR討論。此外,iOS 的對象從未有過的垃圾收集特點。較ARC,在OS-X是沒有用垃圾收集。
下面是一個簡單的ARC例子
#import <Foundation/Foundation.h> @interface SampleClass:NSObject - (void)sampleMethod; @end @implementation SampleClass - (void)sampleMethod { NSLog(@"Hello, World! "); } - (void)dealloc { NSLog(@"Object deallocated"); } @end int main() { /* my first program in Objective-C */ @autoreleasepool{ SampleClass *sampleClass = [[SampleClass alloc]init]; [sampleClass sampleMethod]; sampleClass = nil; } return 0; }
當我們編譯上面的程序,我們會得到下面的輸出。
2013-09-28 04:45:47.310 demo[8385] Hello, World! 2013-09-28 04:45:47.311 demo[8385] Object deallocated