注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Object-C的开发之二NSAutoreleasePool的原理和用法  

2015-12-24 19:55:21|  分类: IOS |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Object-C的开发之二NSAutoreleasePool的原理和用法

 

Object-C的程序中,在开头结尾一般都会有这样一行代码:

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // [1.5]
// insert code here...

[pool release];

那么它们有什么作用的,目的是什么呢?为什么在C的程序里就没有类似的东西呢?

CC++开始,指针在编程的过程中就是一个让人非常头痛的事情。为了解决这个问题,从Java 开始,一系列的高级语言都使用了垃圾回收机制,所以,Object-c 不可避免的也引入了这种解决机制。

Autorelease Pool全名叫做NSAutoreleasePool,是OC中的一个类。autorelease pool并不是天生就有的,你需要手动的去创建它。一般地,在新建一个iphone项目的时候,xcode会自动地为你创建一个Autorelease Pool,这个pool就写在Main函数里面。在NSAutoreleasePool中包含了一个可变数组,用来存储被声明为autorelease的对象。当NSAutoreleasePool自身被销毁的时候,它会遍历这个数组,release数组中的每一个成员(注意,这里只是release,并没有直接销毁对象)。若成员的retain count 大于1,那么对象没有被销毁,造成内存泄露。默认的NSAutoreleasePool 只有一个,你可以在你的程序中创建NSAutoreleasePool,被标记为autorelease的对象会跟最近的NSAutoreleasePool匹配。可以嵌套使用NSAutoreleasePool

但是,这种机制也不是没有缺点的:

即使NSAutoreleasePool看起来没有手动release那么繁琐,但是使用NSAutoreleasePool来管理内存的方法还是不推荐的。因为在一个NSAutoreleasePool里面,如果有大量对象被标记为autorelease,在程序运行的时候,内存会剧增,直到NSAutoreleasePool被销毁的时候才会释放。如果其中的对象足够的多,在运行过程中你可能会收到系统的低内存警告,或者直接crash,这一点和GC回收没有什么本质的区别。

如果把Main函数中的NSAutoreleasePool代码删除掉,然后再自己的代码中把对象声明为autorelease,你会发现系统并不会给你发出错误信息或者警告。用内存检测工具去检测内存的话,你可能会惊奇的发现你的对象仍然被销毁了。其实在新生成一个Run Loop的时候,系统会自动的创建一个NSAutoreleasePool,该NSAutoreleasePool无法被删除。

注意:

xcode4.3引入ARCrelease这块就有些变化,当你使用ARC,就必须将NSAutoreleasePool的地方换成 @autoreleasepool

 关于NSAutoreleasePool的解释官方的最清楚

 Important If you use Automatic Reference Counting (ARC), you cannot use autorelease pools directly. Instead, you use @autoreleasepool blocks instead. For example, in place of:

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init;

 // Code benefitting from a local autorelease pool.

 [pool release];

 you would write:

 @autoreleasepool {

 // Code benefitting from a local autorelease pool.

 }

 @autoreleasepool blocks are more efficient than using an instance of NSAutoreleasePool directly; you can also use them even if you do not use ARC.

[pool drain] [pool release] 的区别:

release,在引用计数环境下,由于NSAutoReleasePool是一个不可以被retain的类型,所以release会直接dealloc pool对象。当pooldealloc的时候,pool向所有在pool中的对象发出一个release的消息,如果一个对象在这个poolautorelease了多次,pool对这个对象的每一次autorelease都会release。在GC环境下release是一个no-op操作(代表没有操作,是一个占据进行很少的空间但是指出没有操作的计算机指令)。

drain,在引用计数环境下,它的行为和release是一样的。在GC的环境下,这个方法调用objc_collect_if_needed出发GC

因此,重点是:在GC环境下,release是一个no-op,所以除非你不希望在GC环境下出发GC,你都应该使用drain而不是使用release来释放pool

1. NSAutoreleasePool实际上是个对象引用计数自动处理器。NSAutoreleasePool可以同时有多个,它的组织是个栈,总是存在一个栈顶pool,也就是当前pool,每创建一个pool,就往栈里压一个,改变当前pool为新建的pool,然后,每次给pool发送drain消息,就弹出栈顶的pool,改当前pool为栈里的下一个 pool

  2. 在程序的入口main函数就调用NSAutoreleasePool,这样保证程序中不调用NSAutoreleasePool,但在退出时自动释放。新开线程最好实现NSAutoreleasePool

  3. NSAutoreleasePool的管理范围是在NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];[pool release];之间的对象

  4. NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];

  当执行[pool autorelease]的时候,系统回进行一次内存释放,把autorelease的对象释放掉,如果没有NSAutoreleasePool , 那这些内存不会释放

  注意,对象并不是自动被加入到当前pool,而是需要对对象发送autorelease消息,这样,对象就被加到当前pool的管理里了。当当前pool接受到drain消息时,它就简单的对它所管理的所有对象发送release消息。

好好学习,天天向上。

  评论这张
 
阅读(216)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017