内存管理大总结
2016-07-20 本文已影响113人
你好自己
1.自动引用计数的概念
- 在OC中采用引用计数机制来管理对象的生命周期.
- 在实际的项目中,我们在函数内使用一个临时的对象,通常是不需要修改它的引用计数的,只需要在函数返回前将该对象销毁即可.
- 引用计数真正排上用场是,对象之间传递和共享数据.遵从引用计数这个规则的话,对象的生命周期的管理就完全可以交给引用计数了.
2.内存管理/引用计数
2.1.1 内存管理的思考方式举例
对办公室照明设备所做的动作和对OC对象所做的动作
对照明设备所做的动作 | 对OC对象所做的动作 | OC方法 |
---|---|---|
开灯 | 生成并持有对象 | alloc/copy/new/mutableCopy等方法 |
需要照明 | 持有对象 | retain方法 |
不需要照明 | 释放对象 | release方法 |
关灯 | 废弃对象 | dealloc方法 |
小结:
- 自己生成的对象,自己持有
- 非自己生成的对象.自己也可以持有
- 不再需要自己持有的对象时释放
- 非自己持有的对象无法释放
不知道的点:
这些有关的OC内存管理的方法,实际上不包括在该语言中,而是包含在Cocoa框架中用于OSX iOS应用开发.Cocoa框架中的Foundation框架类库中的NSObject类担负内存管理的职责.OC内存管理中的alloc/retain/release/dealloc方法分别指代NSObject类的alloc类方法,retain实例方法,release实例方法和dealloc实例方法.
针对小结的内容解释如下:
- 自己生成对象并持有.
举例:NSArray *arr1 = [[NSArray alloc]init]; //取得对象,并持有;
- 非自己生成的对象,即使用alloc/copy/new/mutableCopy以外的方法取得的对象,也可以持有.举例:NSArray *arr2 = [NSArray array];//取得对象,但并不持有;``[arr2 retain];//自己持有对象
- 不再需要自己持有的对象时释放.举例
[arr1/arr2 release];
特殊的是 针对arr1,自己生成并持有的对象,可以采用[arr1 autorelease];
,因为autorelease提供这样的功能,使对象在超出指定的生存范围时能够自动并正确的释放(调用release方法). - 无法释放非自己持有的对象:如果对象的引用计数已经为0,则不能再次释放,非自己持有的对象更不能释放.
release和autorelease的区别
release | autorelease |
---|---|
对象立即释放 | 对象不立即释放 |
注册到autoreleasepool中,pool结束时自动调用release
2.1.2 alloc/retain/release/dealloc实现
- 在OC的对象中存有引用计数这一整数值(retainCount)
- 调用alloc/new/copy/mutableCopy/retain方法后,引用计数值+1.
- 调用release后,引用计数-1.
- 引用计数为0时,调用dealloc方法废弃对象
2.1.5 autorelease
autorelease
的具体使用方法如下:
- 生成并持有
NSAutoreleasePool
对象; - 调用已分配对象的
autorelease
实例方法; - 废弃
NSAutoreleasePool
对象.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
id obj = [[NSObect alloc]init];
[obj autorelease];
[pool drain];
尽管如此,当在大量产生autorelease对象时,只要不废弃NSAutoreleasePool对象,那么生成的对象就不能被释放,因此有时候会产生内存不足的现象.
正确的做法是 把自动释放池的创建放在for循环内.代码如下:
for(int i = 0; i< 100000;i++)
{
NSAutoreleasePool *pool = [][NSAutoreleasePool alloc]init];//读入图像,产生大量`autorelease`的对象.
[pool drain];
}
在OC中,也就是Foundation框架时,无论调用哪一个对象的autorelease
实例方法,实际上调用的都是NSObject类的autorelease
实例方法.但是对于NSAutoreleasePool
类,autorelease
实例方法已被该类重载,因此运行就会报错.
//这样写是错误滴
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
[pool autorelease];