本篇博文,將給你們介紹下再Objective-C中如何使用內存管理。一個程序運行的時候,若是不及時的釋放沒有用的空間內存。那麼,程序會愈來愈臃腫,內存佔用量會不斷升高。咱們在使用的時候,就會感受很卡,最終使得程序運行奔潰。所以,將無效的內存及時清理釋放,是很是有必要的。ios
一個對象在最初建立使用,到最後的回收釋放,經歷的是怎樣一個過程呢?
包括:誕生(經過alloc或new方法實現)、生存(接收消息並執行操做)、交友(經過複合以及向方法傳遞參數)、最終死去(被釋放掉)。函數
1、引用計數spa
在對象建立的時候,Cocoa使用了一種叫引用計數的技術:
1)當一個對象被訪問的時候,引用計數器的值就加1,能夠給對象發送一條retain消息;
2)當結束該對象的訪問的時候,引用計數器的值就減1,能夠給對象發送一條release消息;
3)當引用計數器的值爲0的時候,表示再也不訪問該對象,則其佔用的系統內存將被回收重用,會自動給對象發送一條dealloc消息,通常都會重寫dealloc方法;
4)要得到保留計數器當前的值,能夠發送retainCount消息。3d
下面,介紹下幾種方法的聲明和實現方法:指針
首先,新建一個RetainTracker的類,修改類的聲明文件和實現方法:code
1 // RetainTracker.h 2 3 #import <Foundation/Foundation.h> 4 5 @interface RetainTracker : NSObject 6 -(id) retain; 7 -(oneway void)release; 8 -(NSUInteger)retainCount; 9 @end
1 // RetainTracker.m 2 3 #import "RetainTracker.h" 4 5 @implementation RetainTracker 6 -(id) init 7 { 8 if(self == [super init]) 9 { 10 NSLog(@"init: Retain count of %lu.", [self retainCount]); 11 } 12 return (self); 13 } 14 15 -(void) dealloc 16 { 17 NSLog(@"dealloc called. ByeBye!"); 18 [super dealloc]; 19 } 20 21 @end
而後在main.m主函數中調用retain,release,retainCount,dealloc等方法:對象
1 #import <Foundation/Foundation.h> 2 #import "RetainTracker.h" 3 4 int main(int argc, const char * argv[]) 5 { 6 RetainTracker *tracker = [RetainTracker new];// count =1 7 8 [tracker retain]; 9 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 10 11 [tracker retain]; 12 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =3 13 14 [tracker release]; 15 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 16 17 [tracker release]; 18 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =1 19 20 [tracker retain]; 21 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =2 22 23 [tracker release]; 24 NSLog(@"retainCount: %lu", [tracker retainCount]);// count =1 25 26 [tracker release];// count =0, dealloc 27 28 return (0); 29 }
運行結果以下:blog
2、自動釋放繼承
你們都知道,當對象再也不使用的時候,要及時釋放。可是在某些狀況下,弄清楚何時再也不使用一個對象並不容易。若是可以自動釋放就行了。很幸運,Cocoa中有一個自動釋放池(autorelease pool)。細心的朋友能夠發現,在ios5之後,每次新建項目,在main函數中都有個@autoreleasepool方法,這就是將執行的代碼都加到自動釋放池中。內存
NSObject類提供了一個叫作autorelease的方法:
1 -(id) autorelease;
該方法預先設定一條會在將來某個時間發送的release消息。當給一個對象發送autorelease消息的時候,其實是將該對象添加到自動釋放池中。當自動釋放池被銷燬時,會向該池中的全部對象都發送release消息。
那麼,接下來,咱們就用添加到自動釋放池的方法來修改上面的例子。RetainCount類的內容不改變,只要修改main主函數中的內容:
1 /* use auto release pool */ 2 int main(int argc, const char * argv[]) 3 { 4 NSAutoreleasePool *pool; 5 pool = [[NSAutoreleasePool alloc] init]; 6 7 RetainTracker *tracker = [RetainTracker new];// count =1 8 NSLog(@"after new, tracker: %lu", [tracker retainCount]);// count =1 9 10 [tracker retain]; 11 NSLog(@"after retain, tracker: %lu", [tracker retainCount]);// count =2 12 [tracker autorelease]; 13 NSLog(@"after autorelease, tracker: %lu", [tracker retainCount]);// count =2 14 15 [tracker release]; 16 NSLog(@"after release, tracker: %lu", [tracker retainCount]);// count =1 17 NSLog(@"releasing pool"); 18 [pool release]; // 銷燬自動釋放池 19 20 @autoreleasepool { 21 RetainTracker *tracker2; 22 tracker2 = [RetainTracker new]; // count = 1 23 [tracker2 retain]; //count =2 24 [tracker2 autorelease]; // count still = 2 25 [tracker2 release]; //count = 1 26 NSLog(@"auto releasing pool."); 27 } 28 29 return (0); 30 }
運行結果:
tracker對象,經過autorelease消息,將該對象添加到自動釋放池中。當pool自動釋放池發送release消息的時候,pool對象的引用計數器的值爲0,則該自動釋放池要被銷燬,其dealloc方法被調用。使得自動釋放池中的對象也都跟隨其一塊兒被銷燬。
3、內存管理規則
接下來,就給你們介紹下Cocoa的內存管理的幾個規則。
1). 當你使用 new, alloc, copy 方法建立一個對象時,該對象保留計數器的值爲1;
當不使用的時候,要發送一條release或autorelease消息,銷燬對象。
1 NSMutableArray *array; 2 array = [[NSMutableArray alloc] init]; //count =1 3 //use the array 4 [array release];//dealloc, count =0
2). 當你經過別的方法得到一個對象時,假設該對象的保留計數器的值爲1,而已經被設置爲自動釋放,則不須要執行任何操做來清理該對象。
1 NSMutableArray *array; 2 array = [NSMutableArray arrayWithCapacity:17 ]; //count =1, autorelease; 3 //use the array
3). 自動釋放池銷燬的時間是徹底肯定的,它在循環階段是不會被銷燬的。若是一個循環要添加到自動釋放池中的對象不少的時候,能夠考慮循環一部分後先分批釋放掉一些,而後再建立新的自動釋放池。這樣就保證自動釋放池的分配和銷燬操做代價儘量的小。
1 NSAutoreleasePool *pool; 2 pool = [ [NSAutoreleasePool alloc] init ]; 3 int i; 4 for(i=0; i<100000; i++) 5 { 6 id object = [someArray objectAtIndex: i]; 7 NSString *desc = [object descrption]; 8 If(i%100 == 0) 9 { 10 // 每循環一百次就清空一次,而後新建一個自動釋放池 11 [pool release]; 12 pool = [[NSAutoreleaasePool alloc]init]; 13 } 14 } 15 [pool release];
4). 自動引用計數(Auto Reference Counting,即:ARC),若是你啓用了ARC,只要像平時同樣按需分配並使用對象,編譯器會幫你插入retain和release,無需你本身手動添加。ARC只能保留Objective-c的指針對象,即:繼承NSObject的對象。
5). Ios 5 以上,有了歸零弱引用,由於在指向的對象釋放以後,這些弱引用就會被設置爲零(即:nil),而後對象就會像日常指向nil值的指針同樣被處理。使用前要先明確聲明,聲明方法以下:
1 _weak NSString *myString; 或 2 @property(weak) NSString *myString;