iPhone内存管理详细解说系列转载来源:http://keywind.me/blog/2011/05/07/iphonenei-cun-guan-li-xiang-xi-jie-shuo-yi/ 感谢这位作者

做iPhone开发内存管理是避免不了的问题,而且Apple不对iOS进行垃圾回收机制肯定有他的原因.要想清楚了解内存管理,官方文档是最好的资源,于是把这几天看的Memory Management Programming Guide进行整理,一方面做记录,一方面供大家做参考,一些地方翻译的不好还请留言指出.

一:介绍

相对于Mac OS X v10.5+,iOS不支持垃圾回收机制; 相对于普通系统复杂的内存管理,cocoa定义了一些规则来使其变得简单.

二:内存管理规则

基本规则为: 你只能release或autorelease你拥有的object.这句话可具体为:

  • 如果你调用一个方法,这个方法以alloc,new或copy开头;或者你发送一个retain消息,你就拥有这个object.
  • 你可以使用release或者autorelease来放弃一个object的拥有权.

以下两条规则从上面那条延伸而来:

  • 如果你想保存一个接收到的object作为你的实例变量的属性,你必须retain或copy它,通常你使用accessor方法来简化这一步
  • 为了保证接收到的object在它被接收的方法内保持有效,并且安全地返回给这个方法的调用者,你可以使用retain和release或autorelease组合实现

三:object的拥有和丢弃

1.object的所有权政策

一个object可以有一个或更多的拥有者,只要这个object还有至少一个拥有者,它就不被销毁.Cocoa设定以下四条规则:

  • 你拥有你创建的object,使用alloc,new或copy创建
  • 你可以使用retain拥有一个object,来保证你还需要它存在
  • 你必须放弃你不再需要的objects的所有权,使用release或autorelease
  • 你不能尝试放弃你并没有所有权的object

例子:

{Thingamajig *myThingamajig = [[Thingamajig alloc] init];// ...NSArray *sprockets = [myThingamajig sprockets];// ...[myThingamajig release];
}

你用alloc创建myThingamejig,所以要用release释放,而sprockets并不是你创建的,所以不必释放.

2.内幕:retain counts

所有权政策的底层实现靠的是retain counts,每个object都有retain count. 创建一个object,retain count=1; retain这个object,retain count+1; release这个object,retain count-1; autorelease这个object,retain count在未来某个时候-1; 要注意的是,不要可以去查看retainCount的值来判断是否释放,只会误导你,没有意义.

3.Autorelease

Autorelease有Autorelease Pools实现,看例子:

– (NSArray *)sprockets {NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil];return [array autorelease];
}

这个是正确的写法,你alloc了array,但由于你要返回array给这个方法的调用者,所以不能马上释放,又不能不释放,所以有延迟的autorelease就成了最佳选择.而如果:

– (NSArray *)sprockets {NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil];return array;
}

由于array是局部变量,这样你就释放不掉它了.再看:

– (NSArray *)sprockets {NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil];[array release];return array; // array is invalid here
}

由于array已经被释放了,所以也就不能返回给这个方法的调用者了,再看:

– (NSArray *)sprockets {NSArray *array = [NSArray arrayWithObjects:mainSprocket,auxiliarySprocket, nil];return array;
}

你没有所有权,所以不要你释放.

4.共享的objects的有效性

共享的objects既要保证在调用的函数被保持有效,也要保证该函数在把objects return出去的时候因为release而变得无效了.简而言之就是保持objects在你需要的时候保持有效. 要注意两种意外:

(1)当一个object是从集合类(NAArray,NADictionary等等)中移除的:

heisenObject = [array objectAtIndex:n];
[array removeObjectAtIndex:n];
// heisenObject could now be invalid.

当一个object是从集合类中移除的,它就被发送一个release,如果集合类是它唯一的拥有者,那么这个object就被释放了.

(2)当一个object的父object被释放:

id parent = <#create a parent object#>;
// ...
heisenObject = [parent child] ;
[parent release]; // Or, for example: self.parent = nil;
// heisenObject could now be invalid.

当你从object1派生出object2,然后把object1释放,如果object1是object2唯一的拥有者,那么object2也将被释放 为了防止以上两种情况发生,你可以retain一下使拥有拥有权,然后不再需要时释放,比如

heisenObject = [[array objectAtIndex:n] retain];
[array removeObjectAtIndex:n];
// use heisenObject.
[heisenObject release];
5.Accessor(存取器)方法

如果你的类的有一个实例变量是一个object,你需要保证这个object的任何属性在你这个使用这个object时没有被释放.因此需要声明拥有权. 比如你的object允许它的MainSprocket属性被设置,你可以这样实现:

– (void)setMainSprocket:(Sprocket *)newSprocket {[mainSprocket autorelease];mainSprocket = [newSprocket retain]; /* Claim the new Sprocket. */return;
}

需要把之前的mainSprocket先释放,值得注意的是,如果object1调用setMainSprocket,参数是object2的MainSprocket,也就是两者现在共享一个MainSprocket,此时如果object2的MainSprocket改变,object1的也跟着改变.如果你不想这样,你可以:

– (void)setMainSprocket:(Sprocket *)newSprocket {[mainSprocket autorelease];mainSprocket = [newSprocket copy]; /* Make a private copy. */return;
}

这还有个问题,由于以上两个方法都是把原先的MainSprocket给autorelease了,但如果前后两个sprocket是一样的,当这个sprocket被release了那么你再retain或者copy就错了,这时你可以:

– (void)setMainSprocket:(Sprocket *)newSprocket {if (mainSprocket != newSprocket) {[mainSprocket release];mainSprocket = [newSprocket retain]; /* Or copy, if appropriate. */}
}
6.释放object

当一个object的retain count等于0时,它的dealloc方法被调用,用来释放它占有的内存,和其他资源,包括其他实例变量或者说object的拥有权,比如以下的实现释放了mainSprocket和auxiliarySprocket的所有权:

- (void)dealloc {[mainSprocket release];[auxiliarySprocket release];[super dealloc];
}
7.引用的objects

一些方法指定一个object是以引用形式被返回的,(如ClassName * 或 id ),举一些例子:

 initWithContentsOfURL:options:error: (NSData)initWithContentsOfFile:encoding:error: (NSString)executeFetchRequest:error: (NSManagedObjectContext)

这是因为你没有所有权,所以不必释放,例如:

NSString *fileName = <#Get a file name#>;
NSError *error = nil;
NSString *string = [[NSString alloc] initWithContentsOfFile:fileNameencoding:NSUTF8StringEncoding error:&error];
if (string == nil) {// deal with error ...
}
// ...
[string release];
8.retain循环现象

先看图:

以上现象中Document创建一个Page,Page追踪它在哪个Document,如果Document去retain它的Page,而Page也去retain它所在的Document,那么我们知道两者成循环永远释放不掉. 此时解决办法是Document去retain它的page,而Page引用它所在的Document,这被称为”弱引用”.

9.弱引用

可以简单理解为强引用是拥有所有权,而弱引用没有.一些Cocoa典型的弱引用包括:table data sources, outline view items, notification observers, miscellaneous targets 和 delegates. 比如:NSTableView的object不会去retain它的data source,NSApplication不会去retain它的delegate. 你需要注意的是,发送消息给一个你只持有弱引用且已被销毁的object会使程序崩溃,一般条件下被弱引用的object在被销毁时需要通知弱引用的持有者,比如:当你在notification center注册一个object,notification center就持有这个object的弱引用以便notification到来时给它发送消息.此时如果这个object被销毁了,你就要在notification center注销以防止notification center给不存在的object发送消息.

iPhone内存管理详细解说(一)相关推荐

  1. iPhone内存管理详细解说(二)

    继上一篇之后,再来讲述iPhone内存管理的细节. 四:动态内存管理 第四节就内容实质来说跟第三节的object的拥有和丢弃政策是一样的,不过是从以代码为引导的动态形式讲述.所以你会在这一节看到许多代 ...

  2. iphone内存管理

    http://hi.baidu.com/spopavenvldiqyr/item/c8d620b6282c4d4abb0e122a iphone内存管理(一) BY 洋葱头 http://hi.bai ...

  3. iPad/iPhone内存管理四之viewDidUnload/dealloc详细解说

    在进行内存管理时,我们必须要知道这两者的区别时什么. viewDidUnload是在程序接到内存警告的时候调用的,在这时候,我们可以把我们不需要的东西去掉或者让他等于nil. dealloc是在计数等 ...

  4. iphone内存管理(一)

    内存管理在iphone中一直是一个热点话题.通过一段时间的总结我准备与大家分享一下我对内存管理的一点认识和经验. 开始之前先给大家分享一些重要的信息 1.Iphone 3g有128M的内存.但是至少有 ...

  5. iphone内存管理(二)

    (2)尽量避免使用autorelease 虽然autorelease非常简单有用,但是在iphone上一定要谨慎使用,毕竟iphone内存相当有限.autorelease可能会导致直接的隐型内存泄露. ...

  6. ipad/iphone内存管理一

    在我们iPhone/iPad项目中,程序会无缘无故地crash!这让我们非常的苦恼!现在我结合网上的一些资料,并根据自己的理解,和大家一起探讨内存管理这方面的知识.大家有什么不理解的可以直接给我留言. ...

  7. iphone 内存管理2

    iPhone 开发过程中,内存的使用至关重要.不但要合理分配使用内存,还要注意内存泄露的问题, 因为内存泄露会导致程序由于内存不足而崩溃.根据个人开发的经验来看,在开发iPhone程序的过程中,关于内 ...

  8. iphone内存管理的具体问题解决方案

    iPhone 开发内存管理 开发iPhone 应用程序并不难,基本上就是三个词 - "memory, memory, memory" .iPhone OS 对内存的要求很严格,有m ...

  9. iphone 内存管理1

    开发iPhone 应用程序并不难,基本上就是三个词 - "memory, memory, memory" .iPhone OS 对内存的要求很严格,有memory leak ,杀掉 ...

最新文章

  1. python:实现Django简单的网页设计
  2. 拓扑学(代数拓扑学)的有趣应用
  3. 小米android版本升级包下载,小米11 Android 12 Beta 1更新包
  4. 路由选择使用指南之二Padavan
  5. 关于消灭冲击波的蠕虫
  6. 统计当前文件夹下pdf文件的页码总数
  7. ERP标准物料编码规则及方法
  8. Jquery(十)jqueryUI常用功能实战
  9. 无人机无线电干扰原理概论
  10. 学习Java,你能做这些工作:
  11. 影子系统、还原精灵、冰点还原优缺点比较
  12. 浅谈Linux PMIC驱动(一)
  13. cf C. Counting Kangaroos is Fun
  14. 关于dubbo快速开发和服务提供者无法注册上注意点
  15. 小心黑客入侵,六种黑客入侵手机的常见方式
  16. 用户可利用自己的计算机通过因特网采用,2013年春季江苏省高校计算机一级B考试理论题(附答案)_-_副本...
  17. 计算机手速如何学,拼不过手速的你,来学学这些操作
  18. 第8届泰迪杯C题问题总结
  19. JULIA学习材料合集
  20. Denavit-Hartenberg Matrix (D-H矩阵)

热门文章

  1. linux应用程序开发_开发应用程序
  2. uniapp顶部安全距离(包括app)
  3. ingress-nginx更改默认端口/修改apiserver端口范围
  4. 多种子的区域生长算法
  5. 奉劝穷矮搓的宅男,不要再做这五件事了
  6. 论文:Language-Aware Fine-Grained Object Representation for Referring Expression Comprehension
  7. 30个写在脸上的密码
  8. IPsec 配置干货,理论+配置
  9. 微信小程序webview、渲染富文本
  10. java计算机毕业设计教育辅导班信息网服务端MyBatis+系统+LW文档+源码+调试部署