Cocoa 为什么在-[[u PFManagedObjectReferenceQueue]中释放托管对象会崩溃?
我偶尔会看到堆栈跟踪崩溃,如下所示:Cocoa 为什么在-[[u PFManagedObjectReferenceQueue]中释放托管对象会崩溃?,cocoa,core-data,nsmanagedobject,Cocoa,Core Data,Nsmanagedobject,我偶尔会看到堆栈跟踪崩溃,如下所示: 0 libobjc.A.dylib 0x97dc0edb objc_msgSend + 27 1 com.apple.CoreData 0x97edcdc2 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 162 2 com.apple.CoreData 0x97edccbe -[NSManagedObject release] + 94 3 com.apple.CoreFoundation 0x9
0 libobjc.A.dylib 0x97dc0edb objc_msgSend + 27
1 com.apple.CoreData 0x97edcdc2 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 162
2 com.apple.CoreData 0x97edccbe -[NSManagedObject release] + 94
3 com.apple.CoreFoundation 0x9318ef38 CFRelease + 152
4 com.apple.CoreFoundation 0x931a7460 __CFBasicHashStandardCallback + 384
5 com.apple.CoreFoundation 0x931a706e __CFBasicHashDrain + 478
6 com.apple.CoreFoundation 0x9318f101 _CFRelease + 353
7 com.apple.CoreFoundation 0x931bbc6d _CFAutoreleasePoolPop + 253
8 com.apple.Foundation 0x973270aa NSPopAutoreleasePool + 76
9 com.apple.Foundation 0x97326fd2 -[NSAutoreleasePool drain] + 130
10 com.apple.AppKit 0x95087185 -[NSApplication run] + 627
11 com.apple.AppKit 0x9507f2d9 NSApplicationMain + 574
12 com.karelia.Sandvox 0x70001ef6 start + 54
不幸的是,这是相当随机复制。有人知道是什么导致了这样的事故吗?没有人以前在互联网上提到过-\u queueForDealloc:
,这也没用
我对过去的一个类似问题记忆犹新,在这个问题中,这是在托管对象仍然连接有KVO观察器的情况下取消分配托管对象的症状。有人同意吗?
-\u queueForDealloc:
是一种未记录的内部方法。它不时出现在堆栈中,但我们无法直接处理它
您的问题很可能是由于过度释放managedObject造成的。managedObject将由插入、更新或更改对象的上下文强烈保留,因此如果您对对象本身的保留进行微观管理,则可以在上下文释放它之前过度释放它。这会导致托管对象看似随机地消失。相反,您可以过度保留,导致对象在上下文删除后保持不变
我鼓励人们避免保留托管对象,但当您保留托管对象时,请将它们放在类属性或集合(如数组或集合)中。这样,就可以为您处理保留 终于能够在开发机器上重现这个问题,看来这次崩溃是上下文分解过程中早期异常的副作用 事件的顺序类似于:
MOC
正在被解除分配,因此是时候拆除它的内容了MOs
都会变成故障*MO
转换为故障的行为会发送KVO通知MO
MO
s被释放,但异常使核心数据处于意外状态,因此MO
解除分配崩溃MO
的对象可能也会强烈引用MOC
,就像NSObjectController
和朋友一样
*我在测试中发现,核心数据通常在后台线程上执行此操作,可能是为了避免阻塞主线程
MOC
–托管对象上下文MO
–托管对象我有另一个解决方案,所以要解决这个bug。在示例中,ARC的MOC属性类似于(只读、强、非原子)
经过数周的关于时间崩溃的讨论,我找到了osx的解决方案(只需删除非原子元素)
现在它完美了,所有的崩溃都消失了。当在
NSOperation
中使用私有托管对象上下文时,我们遇到了一个类似的问题,我们最终通过修改任何参数和使用私有@autoreleasepool
解决了这个问题。我将在下面进一步阐述
我们当前的设置有一个NSOperationQueue
,它有一个我们在后台进行的长时间运行的计算。该操作首先创建一个私有的托管对象上下文,将父对象集作为主对象上下文,然后去获取它的对象
同时,我们在其他地方有一个单独的NSOperationQueue
,用于同步服务器上的新数据,可能会添加、更新或删除计算操作使用的对象
我们首先在野外看到了一系列这样的崩溃,在本地重新编程的唯一方法是让计算和同步操作连续运行,5-10分钟后,我们会看到类似于以下之一的崩溃:
Thread : Crashed: background queue :: NSOperation 0x18f43c90
0 libobjc.A.dylib 0x36f11f46 objc_msgSend + 5
1 CoreData 0x2928408f -[NSManagedObject release] + 166
2 CoreData 0x2927b4d7 -[_PFArray dealloc] + 94
3 libobjc.A.dylib 0x36f201a9 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 404
4 CoreFoundation 0x294713a9 _CFAutoreleasePoolPop + 16
5 Foundation 0x2a1b6453 -[__NSOperationInternal _start:] + 1058
6 Foundation 0x2a25b44b __NSOQSchedule_f + 186
7 libdispatch.dylib 0x3746d651 _dispatch_queue_drain + 952
8 libdispatch.dylib 0x3746809d _dispatch_queue_invoke + 84
9 libdispatch.dylib 0x3746eba1 _dispatch_root_queue_drain + 320
10 libdispatch.dylib 0x3746fcd7 _dispatch_worker_thread3 + 94
11 libsystem_pthread.dylib 0x375c6e31 _pthread_wqthread + 668
Thread : Crashed: background queue :: NSOperation 0x1db59e80
0 libsystem_kernel.dylib 0x3722edfc __pthread_kill + 8
1 libsystem_pthread.dylib 0x372acd37 pthread_kill + 62
2 libsystem_c.dylib 0x371ce909 abort + 76
3 libsystem_malloc.dylib 0x37258331 szone_size
4 libobjc.A.dylib 0x36bf1621 object_dispose + 20
5 CoreData 0x28ec571d -[_PFManagedObjectReferenceQueue dealloc] + 80
6 CoreData 0x28e5630f -[NSManagedObject dealloc] + 166
7 CoreData 0x28e55217 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 246
8 CoreData 0x28e5508f -[NSManagedObject release] + 166
9 CoreData 0x28e4c4d7 -[_PFArray dealloc] + 94
10 libobjc.A.dylib 0x36c031a9 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 404
11 CoreFoundation 0x29042149 _CFAutoreleasePoolPop + 16
12 Foundation 0x29d88c23 -[__NSOperationInternal _start:] + 1058
13 Foundation 0x29e2dc1b __NSOQSchedule_f + 186
14 libdispatch.dylib 0x371505b1 _dispatch_queue_drain + 952
15 libdispatch.dylib 0x3714af85 _dispatch_queue_invoke + 84
16 libdispatch.dylib 0x37151b9b _dispatch_root_queue_drain + 338
17 libdispatch.dylib 0x37152cd7 _dispatch_worker_thread3 + 94
18 libsystem_pthread.dylib 0x372a9e31 _pthread_wqthread + 668
Thread : Crashed: NSOperationQueue Serial Queue
0 libsystem_kernel.dylib 0x396871f0 __pthread_kill + 8
1 libsystem_pthread.dylib 0x396ef7b7 pthread_kill + 58
2 libsystem_c.dylib 0x39637ff9 abort + 76
3 libsystem_malloc.dylib 0x396aed25 szone_size
4 libobjc.A.dylib 0x390d93a9 object_dispose + 20
5 CoreData 0x2e3d4081 -[_PFManagedObjectReferenceQueue dealloc] + 80
6 CoreData 0x2e3655b7 -[NSManagedObject dealloc] + 166
7 CoreData 0x2e364501 -[_PFManagedObjectReferenceQueue _queueForDealloc:] + 244
8 CoreData 0x2e36437d -[NSManagedObject release] + 164
9 CoreData 0x2e35b867 -[_PFArray dealloc] + 94
10 libobjc.A.dylib 0x390e20d3 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 358
11 CoreFoundation 0x2e5294c1 _CFAutoreleasePoolPop + 16
12 Foundation 0x2ef29999 -[__NSOperationInternal _start:] + 1064
13 Foundation 0x2efcd745 __NSOQSchedule_f + 60
14 libdispatch.dylib 0x395c0cbd _dispatch_queue_drain + 488
15 libdispatch.dylib 0x395bdc6f _dispatch_queue_invoke + 42
16 libdispatch.dylib 0x395c15f1 _dispatch_root_queue_drain + 76
17 libdispatch.dylib 0x395c18dd _dispatch_worker_thread2 + 56
18 libsystem_pthread.dylib 0x396ecc17 _pthread_wqthread + 298
我们多次查看代码,无法确定它崩溃的原因。我们尝试启用NSZombies,但在重新启动之前,内存就会耗尽
我们最终做了以下两件事:
@autoreleasepool
在我们的[privateObjectContext performBlockAndWait:^{…}]
中,我们将所有代码包装在@autoreleasepool{…}
中。这样,在该代码块期间检索到的所有NSManagedObject都将在离开performBlockAndWait之前标记为释放
weakify/strongify
包含NSManagedObjects的任何参数在传递到块之前都会被禁用,在块中会被禁用一次。这样,因为我们不再有对它们的强引用,所以当我们等待
NSOperation
启动时,如果它们变得过时,就可以释放它们。这里有一篇关于weakify/strongify如何工作的好文章:那么你是说我过度发布了这个对象?显然,从堆栈跟踪来看,-release
正在被调用,因此决定是时候释放对象了(我假设核心数据在达到像Cocoa的其余部分一样的保留计数为零时会这样做)。但是,作为解除分配例程的一部分,核心数据解除分配对象,然后向其发送消息?这根本没有道理!我不认为我看到的是你的常规内存管理错误,我认为上下文仍然引用了一个managedObject,该对象由于过度扩展而在先前的耗尽中被杀死。上下文仍然认为对象是活动的,并将对它的引用放入队列中。然后它尝试发送各种删除和释放方法,但对象不再位于内存地址。由于“取消管理”managedObject并将其从对象图中删除是一个复杂的过程,具有许多副作用,因此不正确地删除对象会导致崩溃,具体取决于gra的特定状态