【问题标题】:Is the memory assigned to a strong property released as soon as the property is set to nil?分配给强属性的内存是否会在属性设置为 nil 时立即释放?
【发布时间】:2015-05-25 16:53:10
【问题描述】:

我想知道如何发布强大的属性/iVar。我想澄清为什么我打算这样做。我通过以下任何一种声明拥有一个对象:

@interface MyClass : NSObject 
     @property (readwrite, nonatomic) MyObject *hugeObject;
@end

@interface MyClass : NSObject {
     MyObject *hugeObject;
}
@end

我用某种方法创建这个对象,我用另一种方法等等

- (void)someMethod {
     hugeObject = [[MyObject alloc] init];
}

- (void)someOtherMethod {
     hugeObject = //some function call which returns a MyObject object
     //do something with hugeObject
}

现在,someOtherMethod 被多次调用,每次hugeObject 都必须存储一个新值。我不再需要以前的值,因为它很重,我想摆脱它。于是我就这样修改了someOtherMethod

- (void)someOtherMethod {
     hugeObject = //some function call which returns a MyObject object
     //do something with hugeObject
     hugeObject = nil;
}

我不想等到dealloc,所以将它分配给nil。但是内存使用量还是会上升,只有在程序结束时才会下降。

所以,这就是我的困惑:

  • 分配给强属性的内存是否会在属性设置为 nil 时立即释放?
  • 还是只有ARC自己调用dealloc才释放内存?

问题识别:指向对象的强引用。

解决方案:

我通过将所有strong 属性/iVar 放在@autoreleasepool 中来解决它(如已接受的答案中所建议的那样),以便它们在当前运行循环结束时被释放。调试很有帮助(如 Sulthan 所建议的那样)。

注意:确保@autoreleasepool 是一个本地范围的池,否则这会阻止您期望的内存释放——因为仍然会有一个强引用。

经验教训:

  • 分配nil 后,您只能确定一件事。该对象将收到releaseautorelease 消息。 ARC 不保证是哪一个
  • 如果不再有指向对象的强引用,内存将立即释放(release 情况)或在当前循环结束时(autorelease 情况)。

【问题讨论】:

  • 这个问题有点含糊,因为您说的是“属性”,但您在示例中没有使用任何 Objective-C 属性。
  • ARC 会在你 nil 指向它的强指针时向对象发送 release 消息,但如果其他东西有指向同一个对象的强指针,那么该对象将不会尚未释放。
  • @PhillipMills 这是一个愚蠢的错误。请检查修改后的版本
  • @JoshCaswell 当遇到nil 时,ARC 会立即发送release 消息,还是会等待范围完成? ARC也会将release发送到hugeObject,对吗?如果是这样,那么在分配nil 之前它指向的内存块会发生什么情况?

标签: objective-c memory-management automatic-ref-counting


【解决方案1】:

当分配nil 时,您只能确定一件事。该对象将收到releaseautorelease 消息。 ARC 不保证是哪一个。

如果没有更多指向对象的强引用,内存将立即释放(release 情况)或在当前循环结束时(autorelease 情况) - 这意味着在几分之一秒。

当一些内存没有释放时,通常意味着有另一个强引用持有该对象或对象本身没有正确释放内存。

在您的情况下,您甚至不清楚如何检查对象是否已被释放。最简单的检查是使用dealloc 登录:

- (void)dealloc {
   NSLog(@"Huge object has been removed from memory");
}

请注意,分配给应用程序的内存量不等于应用程序实际使用的内存量。如果您想了解有关内存分配的真实信息,请使用 Inspector 中的 Memory Profiler。

【讨论】:

    【解决方案2】:

    nil 分配给一个强变量确实表明您不再需要该变量所引用的对象,并且如果不存在对该对象的其他强引用 ARC 将快速处理该对象,如果不是立即。

    您的对象可能(见末尾)被 自动释放池引用,这本质上是 ARC 之前遗留下来的历史文物,这将防止您期望的内存释放 - 因为仍然有一个强大的参考。

    主要是为了让人类能够处理手动引用计数 (MRC),自动释放池接受对象的所有权,直到不久的将来某个时候,它才会放弃该所有权。使用自动释放池可以简化 MRC,但在 ARC 时代,它不是必需,但仍然存在 - 很大程度上是因为大量现有代码都依赖它。

    通常的“不太遥远的未来”是事件循环的下一次迭代,但是您可以引入本地范围,当退出时将放弃在该范围内添加到池中的所有对象的所有权。为此,您可以将代码更改为:

    - (void)someOtherMethod
    {
       @autoreleasepool // make a locally scope pool
       {
          hugeObject = //some function call which returns a MyObject object
          //do something with hugeObject
          hugeObject = nil;
       }
    }
    

    如上所述,只有可能您的对象在自动释放池中,如果上述方法不能解决您的问题,那么您对潜伏在某处的对象有另一个强引用...

    HTH

    【讨论】:

    • 好的,有道理。但是,如果我需要 hugeObject 的 prebious 值直到它获得一个新值(很可能在下一个运行循环中),即只有当获得一个新值时,才应该释放前一个值。除了忽略要放在最后的hugeObject = nil 行之外,我还能做什么?
    • 当 runloop 绕过自动释放池中对您的对象的任何引用时,将被丢弃。只有在以下情况下,您才会遇到问题: (a) 您在每个事件中做了很多工作; (b) 您的对象被放置在池中在您进入本地池之前 (@autoreleasepool); (c) 当设置为nil 时,您希望对象真正尽快释放。如果您确定这种情况可能存在,那么一种方法是确保只有一个对您的对象的引用,方法是让“管理器”类持有它并只允许对管理器的多个引用。然后,您的经理可以在请求时放下该对象。
    【解决方案3】:

    分配 nil 将立即发送释放消息。但是,“某些返回 MyObject 对象的函数调用”可能会返回一个自动释放的对象,该对象将具有来自自动释放池的保留计数,直到池消失。您可以通过创建自己的自动释放池来解决这个问题。

    【讨论】:

    • 对不起,我没有得到你。能否请您详细说明一些代码。
    • "分配 nil 会立即发送释放消息" ARC 不保证这一点。
    • 这个答案的一部分是错误的——其余的令人困惑。
    【解决方案4】:

    ""分配给强属性的内存是否在属性设置为 nil 时立即释放?""

    大概吧。它应该在 NSAutoReleasePool 中发布。以下是有关自动释放池及其运行频率的一些信息 来自 Apple 关于 NSAutoreleasePool 的文档:

    Application Kit 在主线程上创建一个自动释放池 事件循环的每个周期的开始,并在 结束,从而释放同时生成的任何自动释放对象 处理一个事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2016-05-06
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      相关资源
      最近更新 更多