内存管理
来源:互联网 发布: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.
//// 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.
-(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.
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 8.装饰设计模式(设计模式笔记)
- UML类图几种关系的总结
- gradle在android studio中应用入门
- CentOS服务进程管理
- Eclipse和Android Studio 快捷键
- 内存管理
- STL中vector的内存分配机制
- 主机与虚拟机之间方便地共享文件----samba
- CentOS任务计划
- TCP客户端和服务端的通信,通过服务端将客户端的小写字母转化成大写发送回来
- hdu2066 最短路 dijkstra
- 笔记python函数,python学习网址
- POJ3304--Segments
- MyBatis传入参数与parameterType