Iphone开发(6) 如何保证不出现内存泄露

Objective-C已经有了垃圾回收机制,但是我们最关心的iso不支持垃圾回收,所以,让我们冷静一下,抛开垃圾回收,自己来管理内存吧。


对象所有权:当一个对象的属性是另外一个对象的时候,换言之,对象A中,有一个属性是对象B,那么,对象A对于对象B,就有对象所有权。那么,在对象A释放的时候,我们必须确保对象B的引用计数减少1(这里不一定是释放对象B,因为对象B还可能在其他地方被引用)。


        一个非常常见的例子就是set方法,把一个对象设置为另外一个对象的属性。在这里,我们必须确保引用计数不混乱,一个良好的实现如下:

//这里还没有解决Car释放的时候,Engine跟着释放
-(void) setEngine:(Engine *) newEngine
{
    [newEngine retain];//增加newEngine的引用计数,标示着Car对newEngine的对象所有权
    [engine release];//释放旧的engine
    engine = newEngine;//引用新的newEngine
}


自动释放池:一个容器,可以装载对象,当池销毁的时候,同时给每一个对象发送release消息(注意这里是发送release消息,而不是直接销毁里面的对象)。当给一个对象发送autorelease消息时,实际上是将该对象添加到NSAutorelease中。当自动释放池被销毁时,会给该对象发送release消息。当然,自动释放池也是一个正常的Objective-C对象,它也遵守引用计数规则。下面有两个例子,可以比较清晰的展示自动释放池的工作现象。


#import <Foundation/Foundation.h>

@interface RetainTracker : NSObject
@end 

@implementation RetainTracker

- (id) init
{
	if (self = [super init]) {
		NSLog (@"init: Retain count of %d.",
			   [self retainCount]);
	}
	
	return (self);
	
} 


- (void) dealloc
{
	NSLog (@"dealloc called. Bye Bye.");
	[super dealloc];
	
} 

@end




int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
	
    RetainTracker *tracker;
    tracker = [RetainTracker new]; // count: 1
	
    [tracker retain]; // count: 2
    //把tracker加入到自动释放池中
    [tracker autorelease]; // count: still 2
    [tracker release]; // count: 1
	
    NSLog (@"releasing pool");
    [pool release]; 
	
    return (0);
}


#import <Foundation/Foundation.h>

@interface RetainTracker : NSObject
@end 

@implementation RetainTracker

- (id) init
{
	if (self = [super init]) {
		NSLog (@"init: Retain count of %d.",
			   [self retainCount]);
	}
	
	return (self);
	
} 


- (void) dealloc
{
	NSLog (@"dealloc called. Bye Bye.");
	[super dealloc];
	
} 

@end




int main (int argc, const char * argv[])
{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
	
    RetainTracker *tracker;
    tracker = [RetainTracker new]; // count: 1
	
    [tracker retain]; // count: 2
    [tracker retain]; // count: 3

    //把tracker加入到自动释放池中
    [tracker autorelease]; // count: still 3
    [tracker release]; // count: 2
	
    NSLog (@"releasing pool");
    [pool release]; 
	
    return (0);
}

请读者自行比较两段代码的输出。


Cocoa内存管理规则:

1.当你使用new、alloc、copy方法创建一个对象时,该对象的保留计数器值为1。当不再使用该对象的时候,你要负责向该对象发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被摧毁。

2.当你通过任何其他方法获得一个对象时,你不需要执行任何操作来确保该对象被清理。就比如这样的语句:NSMutableArray *array = [NSMuableArray arrayWithCapacity:17];你不需要维护array的引用计数,系统会帮你完成(借助于自动释放池)。当然,如果你打算在一段时间内拥有array,你需要给它增加引用计数,并且在不使用的时候减少引用计数。

3.如果你保留了某个对象,你需要释放或者自动释放该对象。必须保持retain方法和release方法的使用次数相等(就必须开始讨论的set方法)。


最后说明两个问题:

1.开始的set方法并没有确保对象销毁时,它的属性对象也销毁,处理的方式很简单,在对象的dealloc方法中,给属性对象发送release。

2.自动释放池也不是可以乱用的,比如在循环中,我们不断的新建对象,而且对象被加载到自动释放池中。那么,当循环很大的时候,被加载到自动释放池的对象并没有被释放,我们的程序占用的内存会持续增长。这时候的处理方法是不断的创建自己的自动释放池,然后释放(释放的时候,里面的对象也跟着释放了),再创建,再释放。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值