【问题标题】:objective-c release time and bad exeaccessObjective-c 发布时间和错误的 exeaccess
【发布时间】:2014-12-05 08:28:52
【问题描述】:

我有这样的代码,在 MRC 中,我相信调用 [t2 description] 会使应用程序崩溃 BAD_EXEACESS,t已经发布了,但是我测试这个的时候,有时候还可以,有时候就崩溃了, 那么问题来了,发布操作是异步的吗?

另一个问题是如果我们有 2 个指针指向同一个自动释放对象, 当自动释放池耗尽时,它很像 [t release] 然后 [t2 release],会不会有问题?

NSObject * t = [[NSObject alloc] init];
NSObject * t2 = t;

[t release];
[t2 description];

【问题讨论】:

    标签: objective-c autorelease


    【解决方案1】:

    向可能被释放的实例发送消息是未定义的行为。未定义意味着无法保证会发生什么。它可能会崩溃。它似乎工作正常。它可能会使 Hello Kitty 在您的计算机上弹出。随便。

    通常当一些动态分配的内存被释放时,内存中的字节保持不变。内存块被简单地标记为可用。所以通常,在新的东西覆盖内存之前,内存位置仍然会“看起来像”它在对象有效之前所做的那样,所以如果你尝试将它当作一个真实的对象来使用,这对于某些类型来说并不少见的操作似乎仍然“成功”。同样,这取决于许多环境条件,例如内存分配方式、对象是否恰好分配在旧对象所在的位置、特定系统等,您不能依赖它。

    那么问题来了,释放操作是异步的吗?

    没有。发布是同步的。但是释放并不一定会释放它。您不知道在对象存在时可能保留并自动释放它的内容。任何 API 都可以保留和自动释放对象。在这种情况下,不太可能有人自动发布它。

    【讨论】:

      【解决方案2】:

      释放操作可能异步工作,这取决于实现。我认为实际上它不是异步的。
      但有时框架会额外引用一个实例。而且这个引用可能只在runloop的下一次迭代之后才被释放,或者它可能只有在收到内存警告时才被释放,甚至可能永远不会被释放。在引擎盖下,系统确实试图优化内存操作。例如,字符串文字永远不会被释放,并且您使用这些字符串文字创建的不可变字符串实际上指向相同的字符串文字。但这是一个实现细节,你不能依赖它。

      基本上有两条规则:

      一旦你将最后一个release 消息发送到一个对象,你就不能访问它。最后,我的意思是从您自己的代码的角度来看。例如:

      NSMutableString *str = [[NSMutableString alloc] initWithString:@"Foo"]; // 1 reference from alloc
      NSLog("%@", str); // good
      [str retain]; // reference count + 1 = 2 total
      NSLog("%@", str); // good 
      [str release]; // reference count - 1 = 1 total
      NSLog("%@", str); // good 
      [str release]; // reference count -1 = 0 total. Object should be considered deallocated
      NSLog("%@", str); // bad. It is no longer safe to access the object
      

      如果您发送autorelease,您可以安全地访问该对象,直到您离开自动释放池的当前范围(如果您不使用自己的池,通常直到您从方法返回)。例如:

      NSMutableString *str = [[NSMutableString alloc] initWithString:@"Foo"]; // 1 reference from alloc
      NSLog("%@", str); // good
      [str retain]; // reference count + 1 = 2 total
      NSLog("%@", str); // good 
      [str release]; // reference count - 1 = 1 total
      NSLog("%@", str); // good 
      [str autorelease]; // some time in the future, but after the current runloop iteration: reference count - 1 = 0 total.
      NSLog("%@", str); // good. because the object will be released later
      

      而且你不能自动释放比你获取的更多的引用。因为如前所述,自动释放基本上会将release 消息的发送延迟到以后。它会被发送。 autorelease 中的 auto 并不意味着系统会检查对象以查看是否需要释放。


      请记住,这些消息被发送到对象,而不是变量。

      您的代码:

      NSObject * t = [[NSObject alloc] init];
      NSObject * t2 = t;
      
      [t release];
      [t2 description];
      

      在内存管理方面是这样的:

      NSObject * t = [[NSObject alloc] init];
      
      [t release];
      [t description];
      

      当您执行此类操作时,您应该发送保留消息并(自动)稍后释放它。我通常使用自动释放。例如:

      NSObject * t = [[NSObject alloc] init];
      NSObject * t2 = [[t retain] autorelease];
      
      [t release];
      [t2 description]; // totally safe to do
      

      或者为了让发生的事情更明显,我们可以将代码分成更多行:

      NSObject * t = [[NSObject alloc] init]; // ref = 1 
      NSObject * t2 = t;  // no change in ref count
      [t retain];  // ref + 1 = 2
      [t autorelease]; // later: ref - 1 = current ref: 2 (-1 scheduled for later)
      
      [t release]; // ref - 1 = 1 (-1 later)
      [t2 description]; // totally safe to do because you still have a reference
      
      return;
      // end of method
      
      // when the autorelease pool is drained the system sends the scheduled release
      // the object is no longer referenced and gets deallocated. 
      

      附注:学习这些东西很好,但在生产代码中最好启用 ARC。 ARC 非常稳定、快速,在复杂的应用程序中它会提高您自己代码的稳定性。您必须编写更少的代码,并且必须减少调试。所以帮自己一个忙,在生产中使用 ARC。

      【讨论】:

        【解决方案3】:

        我猜第一个问题可能与Runloop有关:当你调用release API时,系统会向Runloop发送消息,然后Runloop找到函数并执行它,而不是立即执行。

        第二个问题,当autorelease pool耗尽时,autorelease对象的retain count为-1​​,如果retain count变为0,autorelease对象将被释放。在object-C中,你可以发送msg到nil对象。

        希望能帮到你...

        【讨论】:

        • 指向自动释放对象的指针不会变为 nil。它是一个“悬空指针”,使用该指针向对象发送消息可能会导致崩溃。
        • 第一个,它不在runloop中,第二个,不会变成nil
        猜你喜欢
        • 2011-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-16
        • 1970-01-01
        • 1970-01-01
        • 2011-04-29
        相关资源
        最近更新 更多