【问题标题】:iOS autorelease pool blocksiOS 自动释放池块
【发布时间】:2013-04-18 09:17:21
【问题描述】:

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

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

我不确定我是否完全理解这一点。无论如何,在自动释放池块内创建的任何对象都会在块的末尾释放,因为那是它的生命周期。当对象到达块的末尾时无论如何都将被释放,为什么你需要调用自动释放对象?

为了更清楚,我将举一个例子,说明我的想法:

   @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 以了解内存管理的机制。

【问题讨论】:

    标签: ios memory-management objective-c-blocks autorelease nsautoreleasepool


    【解决方案1】:

    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 
    
    }
    

    【讨论】:

    • 那么这如何回答我的问题?我提供了一个简单的示例,只是为了避免像这样与问题没有太大关系的答案。我还在小例子中添加了 cmets。
    • 通常您只在内存使用率高的函数中使用自动释放池,并且您需要在正常情况下尽快释放它。该段落旨在添加上下文。
    • 好的,所以在非 ARC 环境中,``MyObject *obj = [[MyObject alloc] init];`` 在自动释放池中会发生内存泄漏,但在 ARC 环境中,编译器自动添加对象的释放调用,或者为什么它不再是内存泄漏?
    • 没错,强指针位于函数级别,因此一旦函数退出,就没有强指针,因此对象被释放。如果类中有一个指向它的强指针,它不会被释放,因为该类仍然存在,因此它仍然有一个强指针。在 ARC 中,编译器会为您添加自动释放功能!
    • “自动释放只是从对象中删除保留计数,它不会像在 c 中那样立即“释放”内存。”没有。autorelease 只是将一个对象添加到自动释放池中。 “当自动释放池结束时,所有计数为 0 的自动释放对象都将释放它们的内存。”不,当自动释放池结束时,releases 池中的所有对象。如果 release 之前的保留计数为 1,则任何位置的 release(无论是通过自动释放池还是其他位置)都可能导致对象被释放。
    【解决方案2】:

    (主要是提供一些额外的背景知识;@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 解释的那样,“释放”并不意味着“解除分配”。在块结束时,自动释放池耗尽,这意味着任何待处理的autorelease 调用在块结束时以release 发送。如果这导致对象的保留计数达到 0,则将其释放。

    但是无论上面是否在一个块中,如果没有 ARC,它就是一个泄漏。

    【讨论】:

    • 很好地澄清了泄漏。无论是否包裹着自动释放池,它都是泄漏!
    • 这是否意味着如果我使用 ARC 并从 @autoreleasepool{} 之外的某个位置释放对象,该对象仍然存在,直到 @autoreleasepool 块结束?
    • 这取决于代码。在 autoreleasepool 块的末尾,发送在该块中创建的所有挂起的自动释放。我不知道您的示例中的“释放对象”是什么意思。您可能想整理一个特定的代码示例并发布一个新问题。
    【解决方案3】:

    自动释放池将对象的释放推迟到池的末尾,这避免了它在到达末尾之前被释放的可能性。所以基本上,就是要确保对象在池结束前不会被释放。

    【讨论】:

      猜你喜欢
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-19
      • 2014-09-02
      • 2011-08-04
      • 2021-10-28
      相关资源
      最近更新 更多