我们的应用程序会在我们编写的启用电弧的库中经历双重发布崩溃。运行仪器后,我们发现双重释放发生在由2个线程访问的对象上。
首先,在初始化方法中分配了有问题的对象
在两个线程之外分配objectX = [[NSData alloc] initWithBytes:barcodeBytes length:sizeof(barcodeBytes)];
螺纹a启动,并将objectx添加到nsdictionary。
线程B将ObjectX分配给本地NSDATA指针,并使用RemoveObjectAtaTIndex
从共享的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设备上看到了这一点。
当您将对象存储在两个线程中时,您也隐式保留该对象,因此发行计数匹配。相反,我会看看您是否在某处弄乱了围栏,尤其是如果您不使用GCD。请记住,ARM是一个较弱的架构,因此与x86相比,进入内存订购问题要容易得多。
螺纹A启动,并将objectx添加到nsdictionary。
线程B将ObjectX分配给本地NSDATA指针,并从共享的Nsdictionary
中删除ObjectX
但是您的问题就在那里。您有两个对象objectX
和词典,这些对象被两个不同的线程触摸。这是一个严重的危险,如果您不确切地知道自己在做什么以及如何采取适当的预防措施,那么您就不应该这样做。
,没有看到字典的同步代码很难说。如果数据是不可变的,则可以在第二个线程中创建副本。这将确保它与被删除的字典是一个不同的对象。
还要确保当您突变字典时,所有读取线程都在等待。