【问题标题】:How to stop ARC from releasing twice an object shared by by 2 threads?如何阻止 ARC 释放 2 个线程共享的对象两次?
【发布时间】:2015-07-31 13:32:15
【问题描述】:

我们的应用程序在我们编写的支持 ARC 的库中遇到了双重发布崩溃。运行检测后,我们发现双重释放发生在一个由 2 个线程访问的对象上。

有问题的对象首先在初始化方法中分配到 2 个线程之外

objectX = [[NSData alloc] initWithBytes:barcodeBytes length:sizeof(barcodeBytes)];

线程 A 启动并将 objectX 添加到 NSDictionary。

线程 B 将 ObjectX 分配给本地 NSData 指针,并使用 removeObjectAtIndex 从共享的 NSDictionary 中删除 ObjectX

我们通过运行 NSZombie 注意到的是,ObjectX 现在被自动释放了两次。似乎一个版本是直接在对象上发布的,而另一个版本是在包含它的 NSDictionary 被释放时间接完成的。

首次发布:

   0 libobjc.A.dylib -[NSObject release]
   1 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::pop(void*)
   2 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::tls_dealloc(void*)
   3 libsystem_pthread.dylib _pthread_tsd_cleanup
   4 libsystem_pthread.dylib _pthread_exit
   5 libsystem_pthread.dylib pthread_exit
   6 Foundation +[NSThread exit]
   7 TestApp 0x348e72
   8 Foundation __NSThread__main__
   9 libsystem_pthread.dylib _pthread_body
  10 libsystem_pthread.dylib _pthread_start
  11 libsystem_pthread.dylib thread_start

第二次发布:

   0 libobjc.A.dylib -[NSObject release]
   1 CoreFoundation CFRelease
   2 CoreFoundation -[__NSDictionaryM dealloc]
   3 libobjc.A.dylib objc_object::sidetable_release(bool)
   4 libobjc.A.dylib -[NSObject release]
   5 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::pop(void*)
   6 libobjc.A.dylib (anonymous namespace)::AutoreleasePoolPage::tls_dealloc(void*)
   7 libsystem_pthread.dylib _pthread_tsd_cleanup
   8 libsystem_pthread.dylib _pthread_exit
   9 libsystem_pthread.dylib pthread_exit
  10 Foundation +[NSThread exit]
  11 TestApp 0x348e72
  12 Foundation __NSThread__main__
  13 libsystem_pthread.dylib _pthread_body
  14 libsystem_pthread.dylib _pthread_start
  15 libsystem_pthread.dylib thread_start

最终结果是 ObjectX 被释放了两倍,我们看到了崩溃。有趣的是,我们只在 arm64 设备上看到了这种情况。

【问题讨论】:

    标签: objective-c multithreading automatic-ref-counting


    【解决方案1】:

    当您将对象存储在两个线程中时,您也会隐式保留该对象,因此释放计数匹配。相反,我会看看你是否在某个地方弄乱了线程围栏,特别是如果你没有使用 GCD。请记住,ARM 是一种弱排序架构,因此比 x86 更容易解决内存排序问题。

    【讨论】:

      【解决方案2】:

      线程 A 启动并将 objectX 添加到 NSDictionary。

      线程 B 将 ObjectX 分配给本地 NSData 指针,并从共享的 NSDictionary 中删除 ObjectX

      但是你的问题就在那里。您有两个对象,objectX 和字典,它们被两个不同的线程接触。这是一个严重的危险,如果您不知道自己在做什么以及如何采取适当的预防措施,则根本不应该这样做。

      【讨论】:

      • 你没有分享任何关于你的代码的信息,所以不可能多说。魔鬼在细节中,你根本不提供任何细节。有一些方法可以处理线程之间传递/共享对象,但谁知道你是否在使用它们?
      【解决方案3】:

      如果没有看到字典的同步代码,很难说。如果数据是不可变的,您可以在第二个线程中创建一个副本。这将确保它与被删除的字典不同。

      还要确保当您修改字典时,所有读取线程都在等待。

      【讨论】:

        猜你喜欢
        • 2010-11-08
        • 2021-01-27
        • 2015-10-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-11
        • 2012-12-13
        • 1970-01-01
        • 2012-07-02
        相关资源
        最近更新 更多