`
lovebirdegg
  • 浏览: 171752 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

《iPhone应用程序开发指南(基础篇)》第三章 3.5

阅读更多

原文地址:http://www.aisidechina.com/blog

版权所有:AisideChina

本博客将在今后陆续进行本书的连载,敬请关注!
更多内容请大家购买正版《iPhone应用程序开发指南(基础篇)》

 

3.5            内存管理

        在iPhone开发中,对内存进行正确的管理是非常重要的一个方面。iPhone有128MRAM,但其中约有一半的容量要用于屏幕缓冲和其他系统进程,同时iPhone不支持将内存写到交换文件,所以iPhone只有大约64M的内存用来运行应用程序,且严格受到物理内存量的限制。这样,基本上不容许我们开发的软件存在任何的内存泄露。

iPhone中的内存管理

        由于iPhone对内存严格的要求,所以当一个对象不再需要时,要及时释放它所占用的内存空间。

        Objective-C 的内存管理采用了基于引用计数(Reference Count)这种非常常用的技术。简单讲,每个对象都有一个与之关联的整数,可以将它称为引用计数器或保留计数器,如果要使用一个对象,并确保在使用期间对象不被释放,需要通过函数调用来取得“所有权”,即引用计数器加1,使用结束后再调用函数释放“所有权”,使引用计数器减1。“所有权”的获得和释放,对应引用计数的增加和减少。引用计数为正数时代表对象还有引用,为0时代表可以释放。

        回想前面的例子,[NoteClass alloc]就是为对象分配内存并使它的引用计数器的值为1,而[note1 release]则是负责将note1对象的引用计数值减1,如果检测到note1的引用计数值为0,则note1对象会被释放掉,同时调用dealloc方法。但在这里要牢记的是,在Objective-C中,必须严格使用引用计数机制来控制内存的分配与释放,当对象的引用计数为0时,对象会自动进行释放,并调用dealloc方法,我们绝不可以自行调用dealloc方法。

        下面就来详细说明一下内存是如何管理的。

用于内存管理的方法

        在开发过程中,主要使用以下方法来对内存进行管理。

 获得对象当前引用计数的方法

(1)      -(NSUInteger)retainCount:方法返回当前对象的引用计数值。

获得对象所有权的方法:

(1)      +(id)alloc:这是一个类方法,相信现在你已对它非常熟悉了,它负责为新建的对象分配内存并将新对象返回,同时将该对象的引用计数值设置为1。如果使用了该方法,则被创建的对象要负责调用release方法或autorelease方法来释放对象所有权,从而避免内存泄露。

(2)      – (id)copy:拷贝引用该方法的对象,返回新复制的对象,被赋值的对象引用计数值加1。像obj1 = [obj2 copy],该语句表示复制对象obj2,并将复制结果赋给obj1,同时将obj1的引用计数值加1。

(3)      – (id)retain:将调用该方法的对象的引用计数值加1。

另外,名字中带有alloc, copy, retain 字样的函数,一般都会为引用计数值加1,这是一个在Cocoa中对方法的命名习惯。

释放对象所有权的方法

(1)      – (oneway void)release:负责将对象的引用计数值减1。如果对象的引用计数值减为0,则会调用该对象的dealloc方法,对该对象进行释放。

(2)      – (id)autorelease:某些情况下,我们并不想取得对象所有权,又不希望对象被释放,例如在一个函数中生成了一个新对象并返回:

- (NSString *)description {

         NSString *desc = [[NSString alloc] initWithString:@"iPhone!"];

         return (desc);

}

        像其中的desc对象就是这种情况,description方法需要返回desc变量,所以不能释放它,但在方法之外又没有获取desc的所有权,无法释放。那么应该怎么办呢?

        还记得前面的NSAutoreleasePool * pool吗?该对象被称为自动释放池,如果某个对象obj在自动释放池创建NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]与销毁[pool drain]之间使用[obj autorelease],则该对象就会被放在自动释放池中,表示会被自动释放,当自动释放池被销毁时,将该对象引用计数值减1。所以,我们可以对上面的desc对象做如下修改,将它放到自动释放池中:添加[desc autorelease]语句或将用于初始化的一句改为[[[NSString alloc] initWithString:@"iPhone!"] autorelease]。

       同时,对于没有使用上面讲的三个获得对象所有权方法的对象,将自动放在自动释放池中,如本章一开始的例子中的NSString *note1 = [NSString stringWithString:@"Running at 6 o’Clock"]中的note1对象。

        自动释放池的效率并不高,所以在iPhone开发时,并不建议使用。

        下面,来修改一下Note.m文件,这次所做的修改对于实际记录事情也许并没有多大意义,但它可以很好的帮助我们来理解内存的管理:(具体实例与解析请参看《iPhone应用程序开发指南(基础篇)》)。

其他注意事项

        以上便是关于内存管理大体的方法,下面来看一些关于内存管理的细微之处与实际使用时的小技巧:

(1)        各种容器类如NSArray, NSDictionary, NSSet 等,会将引入的元素的引用计数值加1来获得所有权,而在元素被移除或者整个容器对象被释放时,释放容器内元素的所有权。

(2)        iPhone开发中不支持垃圾回收机制。

(3)        对象最好在需要时再创建,从而节省内存开销。

(4)        绝不可以发送release消息给autorelease对象。

(5)        在需要频繁分配与释放内存的地方(如for循环) ,可以创建自己的NSAutoReleasePool。

内存管理规则

        本节将来总结一下进行内存管理时的主要规则,在今后的开发中遵循这些规则,会使我们少出很多错误。

(1)      获得所有权的函数要和释放所有权的函数一一对应。

(2)      在对象的 dealloc函数中释放对象所拥有的变量并调用父类的dealloc方法。

(3)      永远不要直接调用dealloc来释放对象,只使用引用计数来完成对象的释放。

大道至简,我们应首先牢固掌握这三条,这样,在今后的开发过程中,程序在内存方面应该就会平安无事了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics