《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;
相关文章
相关标签/搜索