如何阻止ARC释放2个线程共享的对象两次?

时间:2015-05-19 15:52:31

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

我们的应用程序在我们编写的启用了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设备上看到了这一点。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

  

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

     

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

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

答案 2 :(得分:0)

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

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