内存管理

来源:互联网 发布:mac app store打不开 编辑:程序博客网 时间:2024/06/10 02:34

当我们创建一个对象时,我们可能在一段时间内,访问这个对象的成员变量,调用这个对象的方法。但当我们不再需要这个对象的时候,就希望系统回收该对象所占用的内存。

在Objective C中,采用引用计数(Reference Counting)来跟踪对象的状态。每个对象都有一个与之关联的整数,叫做引用计数器。当访问某个对象时,该对象引用计数+1,当不再访问该对象的时候,引用计数-1。当对象的引用计数为0时,表示系统不再使用这个对象,系统回收该对象所占内存。


系统销毁一个对象之前,会调用该对象的dealloc方法。如果对象还持有其他对象的引用,此时要重写dealloc方法,在该方法中释放所持有的其他对象(一般是调用被持有对象的release方法)。


悬空指针(Dangling Pointer):当一个对象被销毁,该对象就不再存在,如果此时有一个指针指向这个被销毁的对象,这个指针就叫做悬空指针。调用悬空指针所指向对象的方法时,会出现未知结果!


有关引用计数的方法:

1,retain 引用计数+1

2,release 引用计数-1

3,autorelease 不改变引用计数的值,只是将对象放入自动释放池中

4,retainCount 返回对象的引用计数值


手动引用计数中,改变对象引用计数方式有几种:

1,调用alloc  new  copy  mutableCopy 方法创建对象时,该对象引用计数+1

2,调用对象retain 方法,引用计数+1

3,调用对象release方法,引用计数-1


下面写一个实例来进行手动内存管理,新建一个工程,把自动引用计数(Automatic Reference Counting)关掉

//首先,我们创建一个Phone类,类中有一个实例变量:价格_price//  Phone.h#import <Foundation/Foundation.h>@interface Phone : NSObject {    NSUInteger _price;}@property (assign,nonatomic) NSUInteger price;@end


////  Phone.m//  手动管理内存//#import "Phone.h"@implementation Phone//重写一下dealloc方法,这样当一个对象被销毁之前他会调用dealloc方法,我们就可以看到了-(void)dealloc {    NSLog(@"phone dealloc.");    [super dealloc];}@end

//再创建一个Person类,他拥有一个手机(就是有一个Phone类型的成员变量)//  Person.h//  手动管理内存#import <Foundation/Foundation.h>@class Phone;@interface Person : NSObject {    Phone *_phone;}-(void)setPhone:(Phone *)phone;-(Phone *)phone;@end


////  Person.m//  手动管理内存#import "Person.h"@implementation Person//这里setter方法有问题,留在下面讲!!!-(void)setPhone:(Phone *)phone {    [phone retain];//这里要将Phone类型的值赋给Person的成员变量_phone,将phone的引用计数加一    _phone=phone;}-(Phone *)phone {    return _phone;}//手动管理内存原则:谁(对象或者方法)把一个对象的引用计数+1,谁就要负责‘死前’将该对象引用计数-1-(void)dealloc {    [_phone release];//创建时引用计数加1,这里对应的减1    NSLog(@"person dealloc.");    [super dealloc];}@end

////  main.m//  手动管理内存#import <Foundation/Foundation.h>#import "Person.h"#import "Phone.h"int main(int argc, const char * argv[]) {    @autoreleasepool {        Phone *iPhone=[[Phone alloc] init];//这里用了alloc方法创建对象iPhone,该对象引用计数+1        NSLog(@"iPhone创建:%ld",iPhone.retainCount);                Person *me=[[Person alloc] init];//创建me对象,将该对象引用计数+1        NSLog(@"me:创建%ld",me.retainCount);        [me setPhone:iPhone];//我们写了setPhone方法,把iPhone 对象引用计数+1        NSLog(@"iPhone赋值:%ld",iPhone.retainCount);                [iPhone release];//掉用release方法,引用计数-1        NSLog(@"iPhone release: %ld",iPhone.retainCount);                [me release];//这里释放me对象,引用计数-1。现在me的引用计数为0:第一步,调用dealloc方法(我们重写了此方法,在此方法中iPhone对象调用release,引用计数-1);第二步,销毁对象    }    return 0;}

运行结果如下:

2015-08-25 23:25:35.164手动管理内存[2099:141996] iPhone创建:1

2015-08-25 23:25:35.165手动管理内存[2099:141996] me:创建1

2015-08-25 23:25:35.165手动管理内存[2099:141996] iPhone赋值:1

2015-08-25 23:25:35.166手动管理内存[2099:141996] phone dealloc.

2015-08-25 23:25:35.166手动管理内存[2099:141996] iPhone release: 1

2015-08-25 23:25:35.166手动管理内存[2099:141996] person dealloc.



至此,我们完成了一次手动管理内存!
现在,再考虑一个问题,在调用setPhone方法时,如果我们再传入一个Phone对象,并赋值..........
////  main.m//  手动管理内存#import <Foundation/Foundation.h>#import "Person.h"#import "Phone.h"int main(int argc, const char * argv[]) {    @autoreleasepool {        Phone *iPhone=[[Phone alloc] init];//这里用了alloc方法创建对象iPhone,该对象引用计数+1        NSLog(@"iPhone创建:%ld",iPhone.retainCount);                Person *me=[[Person alloc] init];//创建me对象,将该对象引用计数+1        NSLog(@"me:创建%ld",me.retainCount);        [me setPhone:iPhone];//我们写了setPhone方法,把iPhone 对象引用计数+1        NSLog(@"iPhone赋值:%ld",iPhone.retainCount);                //重新创建一个Phone对象,给me的成员变量_phone赋值        Phone *newPhone=[Phone new];//newPhone +1        [me setPhone:newPhone];        NSLog(@"iPhone count :%ld",iPhone.retainCount);//iPhone count 仍是2        NSLog(@"newPhone count :%ld",newPhone.retainCount); //newPhone +1                [newPhone release];//newPhone -1                [iPhone release];//掉用release方法,引用计数-1        NSLog(@"iPhone release: %ld",iPhone.retainCount);             // 有了newPhone后,这里会将newPhone对象调用release,而iPhone不调用,造成内存泄漏!!!!!!        [me release];//这里释放me对象,引用计数-1。现在me的引用计数为0:第一步,调用dealloc方法(我们重写了此方法,在此方法中iPhone对象调用release,引用计数-1);第二步,销毁对象       }    return 0;}
运行结果如下:

2015-08-25 23:50:37.532手动管理内存[2193:150238] iPhone创建:1

2015-08-25 23:50:37.533手动管理内存[2193:150238] me:创建1

2015-08-25 23:50:37.533手动管理内存[2193:150238] iPhone赋值:2

2015-08-25 23:50:37.534手动管理内存[2193:150238] iPhone count :2

2015-08-25 23:50:37.534手动管理内存[2193:150238] newPhone count :2

2015-08-25 23:50:37.534手动管理内存[2193:150238] iPhone release: 1

2015-08-25 23:50:37.534手动管理内存[2193:150238] phone dealloc.

2015-08-25 23:50:37.534手动管理内存[2193:150238] person dealloc.




为了避免这种问题的出现,在setPhone方法中,将原来的_phone的引用计数减一,修改如下:
-(void)setPhone:(Phone *)phone {//    [phone retain];//这里要将Phone类型的值赋给Person的成员变量_phone,将phone的引用计数加一//    _phone=phone;    if (_phone!=phone) {//两次传入相同的对象,没有什么意义,所以这里加一个判断!        [_phone release];        _phone=[phone retain];    }}

运行结果如下:

2015-08-25 23:49:33.026手动管理内存[2182:149663] iPhone创建:1

2015-08-25 23:49:33.028手动管理内存[2182:149663] me:创建1

2015-08-25 23:49:33.028手动管理内存[2182:149663] iPhone赋值:2

2015-08-25 23:49:33.028手动管理内存[2182:149663] iPhone count :1

2015-08-25 23:49:33.028手动管理内存[2182:149663] newPhone count :2

2015-08-25 23:49:33.028手动管理内存[2182:149663] phone dealloc.

2015-08-25 23:49:33.028手动管理内存[2182:149663] iPhone release: 1

2015-08-25 23:49:33.029手动管理内存[2182:149663] phone dealloc.

2015-08-25 23:49:33.029手动管理内存[2182:149663] person dealloc.






0 0
原创粉丝点击