内存管理详解
Objective-c 提供了三种内存管理方式:manual retain-release (MRR 手动管理),automatic reference counting (ARC,自动引用计数),garbage collection(垃圾回收)。 iOS 不支持垃圾回收;ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;这篇笔记主要讲的是手动管理。
MRR手动管理内存也是基于引用计数的,只是需要开发者发消息给某块内存(或者说是对象)来改变这块内存的引用计数以实现内存管理(ARC技术则是编译器代替开发者完成相应的工作)。一块内存如果计数是零,也就是没有使用者,那么objective-C的运行环境会自动回收这块内存。
口诀
1、谁创建谁释放,如果你通过alloc,new或copy 来创建一个对象,那么你必须调用release或autorelease.
例如,你在一个函数中alloc生成了一个对象,且这个对象只在这个函数中被使用,那么你必须在这个函数中调用release或autorelease.如果你在一个class的某个方法alloc一个成员对象,且没有调用autorelease,那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease,那么在dealloc中什么都不需要做。
2、除了alloc,new或copy 之外的方法创建的对象都被声明了autorelease.
3、谁retain,谁release,只要你调用了retain,无论这个对象是如何生成的,你都要调用release.
1、你初始化(alloc/init)的对象,你需要释放( release)它。例如:
NSMutableArray *array = [[NSMutableArray alloc] init];
后,需要
[array release];
2、你retain或copy的,你需要释放它。例如
[array retain];
后,需要
[array release];
3、dealloc并不将内存释放,也不会将索引计数降低,于是直接调用dealloc反而无法释放内存,在objective-c中,索引计数是起决定性作用的。
对象被创建的时候,引用计数的值为1;
当引用计数为0的时候,对象将被系统统一销毁。
在一定的代码段内,对同个对象所做的copy,alloc,和retain的 *** 作次数应当与 release和autorelease *** 作的次数相等。
使用alloc创建对象,则需要使用完毕后进行释放:
string = [[Nsstring alloc] initWithString:@”Hello”];
[string release];
使用便利构造器创建对象,(如:Nsstring类的 stringWithString方法),则这个对象将被视为已经使用了autorelease,则使用完毕后不需要进行释放:
string = [Nsstring stringWithFormat:@”Hello”];
如果你定义了实例变量,则在你的类中实现-dealloc这个方法来释放他们。
例子:
-alloc / -release
- (voID)printHello
{
NSString *string;
string = [[NSString alloc] initWithString:@"Hello"];
NSLog(string);
// 我们使用alloc来创建了一个string 所以要release它
[string release];
}
便捷构造方法
(voID)printHello { NSString *string; string = [NSString stringWithFormat:@"Hello"]; NSLog(string); // 我们构建这个string的时候,使用了便捷构造方法( convenIEnce constructor ) // 所以我们认为它是 autoreleased的 }
_array = [NSMutableArrayarray];
for (NSUInteger i =0; i <100; i++)
{
NSNumber *convenIEnceNumber = [NSNumbernumberWithInteger:i];
[_arrayaddobject:convenIEnceNumber];
}
在这个例子中,你既不需要release新对象,也不需要retain新对象
在Cocoa中,当向一个集合对象中添加一个对象元素时,集合会主动持有对它的所有权。
而从集合中拿掉一个对象时,集合会主动放弃对它的所有权。
autorelease Pool
UIKit框架已经帮你自动创建一个autorelease pool。大部分时候,你可以直接使用这个pool,不必自己创建;所以你给一个对象发送autorelease 消息,那么这个对象会加到这个UIKit自动创建的pool里。某些时候,可能需要创建一个pool:
1、没有使用UIKit框架或者其它内含autorelease pool的框架,那么要使用pool,就要自己创建。
2、如果一个循环体要创建大量的临时变量,那么创建自己的pool可以减少程序占用的内存峰值。
3、创建线程时必须创建这个线程自己的autorelease pool。
使用alloc和init消息创建pool,发送 drain消息则表示这个pool不再使用。pool的创建和drain要在同一上下文中,比如循环体内。
使用weak reference 来避免retain cycle
对一个对象发送retain消息会创建对这个对象的强引用。如果两个对象都有一个强引用指向对方,那么就形成了一个环(retain cycle)。这个环使得这两个对象都不可能被release。
弱引用指的是一种non-owning的关系,比如简单指针赋值关系。使用弱引用避免了retain cycle。但是弱引用指向的对象已经释放,那么发送消息给它会导致程序崩溃。所以,需要一点点额外的 *** 作来使用弱引用所指的对象。
copy和retain的区别:
copy:建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
那上面是什么该死的意思呢?
copy其实是建立了一个相同的对象,而retain不是:
比如一个Nsstring对象,地址为0x11111,内容为@"bar".
copy到另外一个Nsstring之后,地址为0x2222,内容相同,新的对象retain为1,旧有对象没有变化
retain到另外一个Nsstring之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain是指针拷贝,copy是内容拷贝。
总结以上是内存溢出为你收集整理的内存管理详解全部内容,希望文章能够帮你解决内存管理详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)