内存管理
2015-08-25 22:44
447 查看
当我们创建一个对象时,我们可能在一段时间内,访问这个对象的成员变量,调用这个对象的方法。但当我们不再需要这个对象的时候,就希望系统回收该对象所占用的内存。
在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)关掉
运行结果如下:
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对象,并赋值..........
运行结果如下:
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的引用计数减一,修改如下:
运行结果如下:
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.
在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.
相关文章推荐
- Lua的内存管理浅析
- 深入探讨PHP中的内存管理问题
- Objective-C的内省(Introspection)用法小结
- linux 内存管理机制详细解析
- 解析PHP中的内存管理,PHP动态分配和释放内存
- javascript内存管理详细解析
- JavaScript内存管理介绍
- Cocos2d-x的内存管理总结
- 模拟实现C语言中的内存管理
- javascript错误的认识不用关心内存管理
- Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect实例分析
- Objective-C中NSLog输出格式大全
- Python深入学习之内存管理
- Swift调用Objective-C编写的API实例
- Swift、Objective-C、Cocoa混合编程设置指南
- Objective-c代码如何移植为Swift代码 Objective-c代码转移到Swift过程介绍
- Swift调用Objective-C代码
- 简单说说STL的内存管理
- objective-c中生成随机数的方法
- 在Swift中使用Objective-C编写类、继承Objective-C类