記憶體管理是任何程式設計語言中最重要的過程之一。它是在需要時分配物件的記憶體並在不再需要時取消分配的過程。
管理物件記憶體是一個效能問題; 如果應用程式不釋放不需要的物件,則應用程式會因記憶體占用增加並且效能受損。
Objective-C記憶體管理技術大致可分為兩類 -
在MRR中,通過跟蹤自己的物件來明確管理記憶體。這是使用一個稱為參照計數的模型實現的,Foundation
類NSObject
與執行時環境一起提供。
MRR和ARC之間的唯一區別是保留和釋放,前者是手動處理,而後者則自動處理。
下圖表示記憶體管理在Objective-C中的工作方式範例。
A
類物件的記憶體生命週期如上圖所示。 如您所見,保留計數顯示在物件下方,當物件的保留計數變為0
時,物件將被完全釋放,並且其記憶體將被釋放以供其他物件使用。
首先使用NSObject
中提供的alloc/init
方法建立A
類物件。 現在,保留計數變為1
。
現在,B
類保留了A
類的物件,A
類物件的保留計數變為2
。
然後,C
類拷貝該物件的副本。它被建立為A
類的另一個範例,具有相同的範例變數值。 這裡,保留計數是1
而不是原始物件的保留計數。如圖中的虛線表示。
使用release
方法由C
類釋放複製的物件,並且保留計數變為0
,因此物件被銷毀。
對於初始的A
類物件,保留計數為2
,所以必須釋放兩次才能銷毀它。 這是通過A
類和B
類的釋放語句完成的,它們將保留計數分別減少到1
和0
。 最後,物件就被銷毀了。
擁有建立的任何物件:使用名稱以「alloc」,「new」,「copy」或「mutableCopy」開頭的方法建立物件
使用retain
獲取物件的所有權:通常保證接收到的物件在接收到的方法中保持有效,並且該方法也可以安全地將物件返回給它的呼叫者。在兩種情況下使用retain
-
init
方法的實現中,獲取想要儲存為物件屬性值的物件的所有權。當不再需要它時,必須放棄對擁有的物件的所有權:通過向物件傳送釋放訊息或自動釋放訊息來放棄物件的所有權。 因此,在Cocoa術語中,放棄物件的所有權通常被稱為「釋放」物件。
範例程式碼
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/* 第一個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");
// 應該將物件設定為nil
sampleClass = nil;
return 0;
}
執行上面範例程式碼,得到以下結果 -
2018-11-16 07:02:42.556 main[152785] Hello, World!
2018-11-16 07:02:42.558 main[152785] Retain Count after initial allocation: 1
2018-11-16 07:02:42.558 main[152785] Retain Count after retain: 2
2018-11-16 07:02:42.558 main[152785] Retain Count after release: 1
2018-11-16 07:02:42.558 main[152785] Object deallocated
2018-11-16 07:02:42.558 main[152785] SampleClass dealloc will be called before this
在自動參照計數或ARC中,系統使用與MRR相同的參照計數系統,但它在編譯時為我們插入適當的記憶體管理方法呼叫。 強烈建議將ARC用於新專案。 如果使用ARC,通常不需要理解本文件中描述的底層實現,儘管在某些情況下它可能會有所幫助。 有關ARC的更多資訊,請參閱ARC發行說明。
如上所述,在ARC中,不需要新增release
和retain
方法,因為編譯器會對此進行處理。 實際上,Objective-C的基本過程仍然是相同的。 它在內部使用保留和釋放操作,使開發人員更容易編碼而無需擔心這些操作,這將減少寫入的程式碼量和記憶體洩漏的可能性。
還有另一個原則叫做垃圾收集,它在Mac OS-X中與MRR一起使用,但由於它在OS-X Mountain Lion中的棄用,它還沒有與MRR一起討論過。 此外,iOS物件從未擁有垃圾收集功能。 使用ARC,OS-X中也沒有使用垃圾收集。
這是一個簡單的ARC範例。 請注意,這不適用於線上編譯器,因為它不支援ARC。
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (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;
}
執行上面範例程式碼,得到以下結果 -
2018-10-28 08:45:17.210 demo[8385] Hello, World!
2018-10-28 08:45:17.211 demo[8385] Object deallocated