了解Cocoa中内存如何管理是本文要介绍的内容,不多说,直接进入话题。今天我们来谈论Cocoa中关于内存管理的问题。这个问题无论是对于桌面开发还是移动开发都非常重要。
尤其是对iPhone开发来说,更尤为重要。为什么说更呢?因为iPhone是移动终端,它不会象Mac一样有很强的CPU,更不会有很多的内存,这就使iphone程序在内存开销上变得非常昂贵。所以,如果我们不加限制的话,我们的开发的程序很可能会使用掉所有的内存,这样我们就没有空闲的内存来运行其他的程序了,谁都不想在运行程序的时候接不了电话,对吧。所以,在这里,我们要强掉内存管理的重要性。
当然,随着iPhone的更新换代,它的CPU会越来越强大,它的内存会越来越多,即使是这样我们也要养成良好的编程习惯,随时考虑内存问题,开发出没有内存泄露的完美的程序。
今天,我们将从两方面讨论内存这个问题。
1、如何创建对象并向它分配内存?
2、如何释放对象占用的内存?
一、如何分配内存
我们使用alloc和init方法来创建对象并初始化对象,这其中就包含了向对象分配内存。我们看一下下面的代码。
- Fraction *myFract = [[ Fraction alloc ] init];
其中Fracion是一个类,上面语句创建了Fraction类的一个新对象myFract,并给它分配了内存空间用来存储在它当中的变量。这是一个很简单的语句,在你想给任何一个类创建新的对象时,你都可使用这条语句。
还有很多其他的方法可以用来获得对象,就像前面做的一样,下面是一些例子。
- NSString *newDisplay = [display.text stringByAppendingString:digit];
- NSArray *keys = [dictionary allKeys];
- NSString *lowerString = [string lowercaseString];
- NSNumber *n = [NSNumber numberWithFloat:42.0];
- NSDate *date = [NSDate date];
上面的这些方法都会获得对象,还有很多类似的方法,现在,关键问题出来了,我们给这些对象分配了内存,那谁负责释放他们呢?我们来看看下面的东西。
二 、内存的释放
好了,我们接着上面留下的问题,为了解决这个问题,我要介绍下面几个概念。
a、引用计数器(Reference Counting)
b、引用所有权(Ownership)
c、自动释放池(Autoreleasepool)
引用计数器
我们在谈论对象内存的释放,可到底什么时候我们需要释放对象呢?判断对象是否需要释放的唯一标准是:对象不再被使用,它在程序中没有了利用的价值。我们就是使用引用计数器来判断对象在程序中是否还在被使用。
引用计数器就是用来跟踪对象的引用次数,它是这样工作的:当一个对象被创建时,将它的引用次数设置为1,每当程序中的其他对象或方法调用它时,它的计数器就加1。当调用结束时,计数器就减1,这就意味着这个方法对对象的使用结束了。当一个对象的计数器为0的时候,表示这个对象不被程序中任何其他的对象和方法调用,也就是程序不再需要它,这时候我们就可以安全的释放它了。
这里面有两个非常重要的方法,一个是retain(保持),另一个是release(释放)。当对象被引用时,我们向对象发送retain方法,使它的计数器加1.当引用结束后,我们向他发送release方法,使它的计数器减1.这样看来,retain和release方法是成对出现的,每一个retain对应一个release,同理,我们还会有一个release方法和计数器的初始值1相对应,这样才能保证计数器可以减到0,确保对象可以被释放。
所有权(Ownership)
你可能对上面的介绍感到有些抽象,难于理解。下面我们介绍所有权的概念,它会有助于你对计数器的理解。在计数器的介绍中我们说一个对象被一个对象所引用,例如对象myFract被对象myNumbe所引用,我们就说myNumbe对Fract有所有权。对应的,当myNumbe不再使用Fract时,它就要放弃对Fract的所有权。当程序中没有对象和方法对Fract有所有权时,对象Fract就可以被释放了。这里还要强调一点,一个对象可以被多个对象或方法所拥有,也就是说程序中可以有多个对象或方法同时对同一个对象拥有所有权。
好了,接下来我们把计数器和所有权联系在一起。
当对象A被对象B(或方法)调用时,对象B向A发送retain消息来获得对A的所有权,于此同时A的计数器加1;
当B对A的调用结束后,对象B向A发送release消息来放弃对A的所有权,与此同时A的计时器减1;
当A的计数器为0时,也就是程序中不再有人对A有所有权,这时,A就可以被安全的释放。
现在明白了么?
自动释放池
我们来说最后一个概念,我们要把这个问题和前两个概念联系在一起,因为它们都是Cocoa内存管理的组成部分。我们来谈自动释放池。
系统使用自动释放池来跟踪对象,以便以后释放它们。有些对象在你使用完之后,你并不确定你是否还会再次使用到它,如果这时候就释放了,以后在用到它的时候就会很麻烦。自动释放池可以解决这个问题。因为你可以通过标记把对象添加到自动释放池中,在自动释放池被释放的时候,它所包含的对象也会被一起释放。当对象被添加到释放池中后,它并没有被释放,所以你还可以使用它,但你也不用担心自己忘记释放它,应为你已经把它添加到释放池中了。
下面这条语句用来建立释放池:
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
这条语句用来释放自动释放池:
- [pool drain];
要把对象添加到自动释放池中,可以使用下面的语句:
- [ myFract autorelease] ;
有一点要注意,把对象添加到释放池并不会使对象的计数器加1.
三、内存管理规则摘要
a释放对象,可以释放它所占有的内存,如果你的程序在运行时创建了很多对象,应该关注对象的释放,良好的规则是,不再使用创建或保持的对象时,就释放它们。
b发送一条release消息不一定销毁对象,当一个对象的引用计数器为0时,才销毁这个对象。系统通过向该对象发送一条dealloc消息来释放它所占的内存。
c自动释放池用于在释放本身时自动释放池中的对象。
d如果你的方法中不再需要一个对象,但需要返回它时,那么向其发送一条autorelease消息,将它标记为以后释放。
e如果使用alloc和copy方法直接创建对象,则由你负责释放它。每次retain对象,应该release或autorelease它。
小结:了解Cocoa中内存如何管理的内容介绍完了,以上这些是Cocoa内存管理的基本概念,也是最为重要的概念。对内存管理的关注要贯穿程序开发的始终,我们要一再的强调它的重要性。最后希望本文对你有所帮助!