標籤:
概述
開發的過程中,很多程式員都不會注意管理對象或者變數的記憶體,導致系統或者應用運行一段時間,就很慢了,或者崩潰。下面我們一起聊聊編程過程中的記憶體是如何進行管理的。
記憶體管理組件含那些方面?
有效記憶體管理,通常包含兩方面內容:
記憶體配置:當程式建立對象時需要為對象分配記憶體。採用合理的設計,盡量的減少對象的建立,並減少對建立過程中的記憶體開銷。
記憶體回收:當程式不再需要對象時,系統必須及時回收這些對象所佔用的記憶體,以便程式可以再次使用這些記憶體。
iOS 5 之前,iOS開發人員,需要話費精力去處理記憶體回收相關的問題。iOS 5 之後,引入了心的特性:自動引用技術(ARC)。通過 ARC ,程式員可以不需要關注記憶體回收這塊內容,可以大大的提高開發的效率。
Objective-C 記憶體回收機制有以下方式
手動引用計數
目前建立的項目預設都是ARC的,如何可以將項目改為 MRC 模式呢?
建立項目,開啟項目的配置介面,選擇 Target -> Buld Setting -> 搜尋 automatic reference , 設定
將自動引用計數設定為NO,就可以手動引用計數了。
Objective-C 採用來一種被稱為引用計數的計數來跟蹤對象的狀態:每個對象都有一個與之關聯的整數,這個整數被稱為引用計數器。正常情況下,當一段代碼需要訪問某個對象時,該對象的引用計數加1;當這段代碼不在訪問改對象時,改對象的引用計數減1,表示這段代碼不在訪問該對象。當對象的引用計數為0的時候,表示程式已經不在需要該對象,系統就會回收改對象所佔用的記憶體。
系統在銷毀該對象之前,會自動調用改對象的 delloc 方法來執行一些回收操作。
當對象唄銷毀之後,此時該對象已經不再存在;如果有一個指標指向這個被銷毀的對象,這個指標酒杯稱為懸null 指標,也稱為野指標,殭屍指標,調用該指標指向對象的方法時,程式往往會出現未知的結果,甚至導致程式崩潰。
在手動引用計數中,改變對象的引用計數的方式如下:
- 當程式調用方法名以 alloc、new、copy、mutableCopy 開頭的方法來建立對象時,該對象的引用計數加1.
- 當程式調用對象的 retain 方法時,該對象的引用計數加1.
- 當程式調用對象的 release 方式時,該對象的引用計數減1.
NSObject 中提供了有關引用計數的方法:
- retain: 引用計數+1
- release:引用計數-1
- autorelease:不改變該對象的引用計數器的值,只是將對象添加到自懂釋放池中。
- retainCount:返回該對象的引用計數的值。
看看測試代碼:
1 // 2 // Item.m 3 // MRC 4 // 5 // Created by 萬齊鶼 on 15/7/27. 6 // Copyright (c) 2015年 萬齊鶼. All rights reserved. 7 // 8 9 #import "Item.h"10 11 @implementation Item12 13 - (instancetype)init14 {15 self = [super init];16 if (self) {17 NSLog(@"init方法中,引用計數為:%ld", self.retainCount);18 }19 return self;20 }21 22 -(void)dealloc23 {24 NSLog(@"調用銷毀的方法");25 [super dealloc];26 }27 28 @end
//// main.m// MRC//// Created by 萬齊鶼 on 15/7/27.// Copyright (c) 2015年 萬齊鶼. All rights reserved.//#import <Foundation/Foundation.h>#import "Item.h"int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... Item * item = [[Item alloc] init]; // 引用計數1 NSLog(@"%ld", item.retainCount); [item retain]; // 引用計數2 NSLog(@"%ld", item.retainCount); [item retain]; // 引用計數3 NSLog(@"%ld", item.retainCount); [item release]; // 引用計數2 NSLog(@"%ld", item.retainCount); [item retain]; // 引用計數3 NSLog(@"%ld", item.retainCount); [item release]; // 引用計數2 NSLog(@"%ld", item.retainCount); [item release]; // 引用計數1 NSLog(@"%ld", item.retainCount); [item release]; // 引用計數0 } return 0;}
啟動並執行結果:
手工記憶體管理規則的總結
- 如果需要保持一個對象不被銷毀,可以使用 retain 。在使用完對象後,需要使用 release 進行釋放。
- 給對象發送 release 訊息並不會銷毀這個對象,只當這個對象的引用計數減至0時,對象才會被銷毀。然後系統會發送 dealloc 訊息給這個對象用語釋放對象。
- 對使用了 retain 或者 copy、mutableCopy、alloc 或 new 方法的任何對象,以及具有 retain 和 copy 特性的屬性進行釋放,需要覆蓋 dealloc 方法,使得對象被釋放的時候能夠釋放這些案例變數。
- 在自動釋放池被清空時也會為自動釋放的對象做些事情。系統每次都會在自動釋放池被釋放時發送 release 訊息給池中的每個對象。如果池中的對象引用計數降為0,系統會發送 dealloc 訊息銷毀這個對象。
- 如果在方法中不再需要用到這個對象,但需要將其返回,可以給這個對象發送 autolease 訊息用意標記這個對象延遲釋放。autolease 訊息並不會影響到對象的引用計數。
- 當應用終止時,記憶體中的所有對象都會被釋放,不論它們釋放在制動釋放池中。
- 當開發應用程式時,隨著應用程式的運行,自動釋放池會被建立和清空。在這種情況下,如果要時自動釋放池被清空後自動釋放的對象還能夠存在,對象需要使用 retain 方法,只要這些對象的引用計數大於發送 autorelease 訊息的資料,就能搞在池清理後生存下來。
Objective-C 記憶體管理