《objective-c基礎教程》學習筆記(十)—— 內存管理

  本篇博文,將給你們介紹下再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;
相關文章
相關標籤/搜索