iOS自动释放池块

17

我在阅读苹果公司的关于内存管理的文档时,看到了自动释放池块,这让我开始思考。

 Any object sent an autorelease message inside the autorelease pool block is  
 released at the end of the block.

我不确定我完全理解这个问题。在自动释放池块内创建的任何对象都会在块结束时被释放,因为这是它的生命周期。当对象到达块的结尾时,它将自动释放,那么为什么还需要调用autorelease方法呢?

为了更清楚地说明,我将给出一个例子:

   @autoreleasepool {

    MyObject *obj = [[MyObject alloc] init]; // no autorelease call here

    /* use the object*/
   //....
   // in the end it should get deallocated because it's lifespan ends, right?
   // so why do we need to call autorelease then?!
  }

注意:请不要告诉我因为ARC的存在我们不需要做一些事情,因为ARC会自动处理它们。我完全意识到这一点,但我想在短暂的时刻内先放置ARC,以便理解内存管理机制。

3个回答

31

Autorelease只是从对象中移除保留计数,不像在C语言中立即“释放”内存。当自动释放池结束时,所有计数为0的自动释放对象将被释放其内存。

有时你会创建许多对象。例如,在循环中每次迭代都创建新的字符串并向其中添加新数据。你可能不需要之前版本的字符串,并希望释放这些占用的内存。通过显式使用自动释放池,而不是等待其自然完成,可以实现此目的。

//Note: answers are psudocode

//Non Arc Env
@autoreleasepool 
{

    MyObject *obj = [[MyObject alloc] init]; // no autorelease call here
    //Since MyObject is never released its a leak even when the pool exits

}
//Non Arc Env
@autoreleasepool 
{

    MyObject *obj = [[[MyObject alloc] init] autorelease]; 
    //Memory is freed once the block ends

}
// Arc Env
@autoreleasepool 
{

    MyObject *obj = [[MyObject alloc] init]; 
    //No need to do anything once the obj variable is out of scope there are no strong pointers so the memory will free

}

// Arc Env
MyObject *obj //strong pointer from elsewhere in scope
@autoreleasepool 
{

    obj = [[MyObject alloc] init]; 
    //Not freed still has a strong pointer 

}

1
那这怎么回答我的问题?我只是提供了一个简单的例子,只是为了避免像这样的回答与问题没有什么太大关系。我也在小例子中添加了注释。 - Teo
1
通常情况下,autorelease池仅在内存使用量高且需要比正常情况下更快释放时的函数中使用。这段文字旨在添加上下文。 - Kibitz503
1
准确地说,强指针是在函数级别上的,因此一旦函数退出,就没有强指针了,因此对象被释放。如果类中有一个指向它的强指针,那么它将不会被释放,因为类仍然存在,因此它仍然有一个强指针。在ARC中,编译器会为您添加自动释放功能! - Kibitz503
3
"Autorelease只是从对象中删除一个保留计数,它不像在C语言中立即"释放"内存。"不,autorelease只是将对象添加到自动释放池中。"当自动释放池结束时,所有计数为0的自动释放对象将释放它们的内存。"不,当自动释放池结束时,它会释放池中的所有对象。release可以在任何地方(无论是由自动释放池还是其他地方)调用,如果release之前的保留计数为1,则可能导致对象被释放。 - newacct
这个答案需要修改以修复@newacct提到的错误。 - kevlar
显示剩余4条评论

6
(主要是提供一些额外的背景信息;@Kibitz503会给你正确的答案。)
@autoreleasepool {

  MyObject *obj = [[MyObject alloc] init]; // no autorelease call here

  /* use the object*/
  //....
  // in the end it should get deallocated because it's lifespan ends, right?
  // so why do we need to call autorelease then?!
}

PS: 请不要告诉我因为ARC我们不需要做一些事情,因为ARC会自动处理。我完全意识到这一点,但我想暂时将ARC放在一边,以便了解内存管理机制。
好的,让我们不考虑ARC。在上面的例子中,在没有ARC的情况下,obj不会被释放。只有因为ARC添加了额外的release调用,可能会被释放(根据你的示例,实际上我们不知道use the object中发生了什么)。
正如@Kibitz503所解释的那样,“release”并不意味着“dealloc”。在块的末尾,autorelease池排空,这意味着任何未完成的autorelease调用都会在块的末尾作为release发送。如果导致对象的保留计数达到0,则它将被释放。
但无论上述内容是否在块中,没有ARC都会造成泄漏。

关于泄漏的澄清很好。无论是否使用自动释放池包装它,这都是一个泄露问题! - Kibitz503
这是否意味着,如果我使用ARC并从“@autoreleasepool {}”之外的某个地方释放对象,该对象仍然存在直到@autoreleasepool块的结束? - Michael
这取决于代码。在autoreleasepool块的末尾,该块中创建的所有待处理的自动释放对象都会被发送。我不知道你的例子中“释放一个对象”的意思是什么。你可能想组合一个具体的代码示例并发布一个新问题。 - Rob Napier

1

自动释放池会延迟对象的释放直到池子结束,这样可以避免对象在到达池子末尾之前被释放的可能性。因此,它基本上是为了确保对象不会在池子结束之前被释放。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接