記憶體管理是任何編程語言中最重要的過程之一。它是在需要時分配對象的記憶體並在不再需要時取消分配的過程。
管理對象記憶體是一個性能問題; 如果應用程式不釋放不需要的對象,則應用程式會因記憶體佔用增加並且性能受損。
Objective-C記憶體管理技術大致可分為兩類 -
- “手動保留或釋放”或MRR
- “自動參考計數”或ARC
1. “手動保留釋放”或MRR
在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
。 最後,對象就被銷毀了。
2. MRR基本規則
擁有創建的任何對象:使用名稱以“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
3. “自動參考計數”或ARC
在自動引用計數或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