autorelease的对象什么时候被回收

主线程有个事件循环。每次有事件的时候,由cocoa框架调用我们写的代码,再回到cocoa框架。NSAutoreleasePool其实是由cocoa框架管理的,当出了我们写的代码,回到框架的时候,放入NSAutoreleasePool的对象就会由框架调用release, 这样就保证跑我们代码的时候,对象是会存在的,出了我们的代码,对象也能够正常地被释放。

比如

系统代码(事件激发)

funA()

funB()

funC()

funD()

系统代码(等待事件)

在funA, funB, funC, funD中,无论调用多少层,也是用户写的代码。autorelease的对象还是存在的。下一次事件激发的时候,上一次事件的对象是不存在的,因为已经被系统框架调用release回收了。除非你自己调用了retain, 自己调用了一次retain, 就应该自己来调用一次release, 这样也没有违背上面说的原则。

自动释放池的缺点:它延缓了对象的释放,在有大量自动释放的对象时,会占用大量内存资源。因此,你需要避免将大量对象自动释放。并且,在以下两种情况下,你需要手动建立并手动销毁掉自动释放池:

1.当你在主线程外开启其它线程时:系统只会在主线程中自动生成并销毁掉自动释放池。(runloop未开启)

2.当你在短时间内制造了大量自动释放对象时:及时地销毁有助于有效利用iPad上有限地内存资源


iOS的运行时是由一个一个runloop组成的,每个runloop都会执行下图的一些步骤:

可以看到,每个runloop中都创建一个Autorelease Pool,并在runloop的末尾进行释放,

所以,一般情况下,每个接受autorelease消息的对象,都会在下个runloop开始前被释放。也就是说,在一段同步的代码中执行过程中,生成的对象接受autorelease消息后,一般是不会在代码段执行完成前释放的。

当然也有让autorelease提前生效的办法:自己创建Pool并进行释放

NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];

NSArray* array = [[[NSArrayalloc] init] autorelease];

[pool drain];

上面的array就会在[pool drain]执行时被释放。

所以对于你遇到的问题,可以在for循环外嵌套一个Autorelease Pool进行管理,例如

NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];

for(inti =0; i <10000; i++)

{// ...}

[pool drain];

但由于你提到了生成的每个实例可能会比较大。只在循环外嵌套,可能导致在pool释放前,内存里已经有10000个实例存在,造成瞬间占用内存过大的情况。

因此,如果你的每个实例仅需要在单次循环过程中用到,那么可以考虑可以在循环内创建pool并释放

for(inti =0; i <10000; i++)

{NSAutoreleasePool* pool = [[NSAutoreleasePoolalloc] init];

// ...[pool drain];}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容