我正在使用 NSOperation 和 NSOperationQueue 执行一系列操作,所有操作都相互依赖(2 对 1、3 对 2 等)。创建操作后,我设置了依赖项。队列完成时我遇到了问题:程序在代码的 _release 部分崩溃,显然是在 NSOperations 被释放时。请注意,它们都在队列的最后被释放,因为只有在最后一个依赖于倒数第二个之后,它们才能被释放。如果我删除任何依赖项,代码运行良好。如果我将 waitUntilFinished: 更改为 NO,它会崩溃,如果它是 YES,它不会。
我已将问题隔离到以下代码,该代码不使用我的任何自定义类。默认情况下,NSOperation 是一个完全不做任何事情的类。然而,当所有操作都完成后,这仍然会崩溃。因此,看来我没有正确使用 NSOperationQueue 但看不出有什么问题。我在 10.9 上运行,我注意到通常 Maverick 10.9 比 10.8 对这些问题更敏感。
我使用菜单项从主线程调用此方法:
- (void) testOperations:(id)object
{
NSOperationQueue* queue = [ [ NSOperationQueue alloc ] init ];
NSMutableArray* array = [ NSMutableArray array ];
for ( int i = 0; i < 10000; i++)
[ array addObject: [[[ NSOperation alloc ] init ] autorelease ] ];
for ( int i = 1; i < [ array count ]; i++)
[[ array objectAtIndex:i ] addDependency:[array objectAtIndex:i-1]]; // remove this and no crash
[ queue addOperations: array waitUntilFinished:NO ]; // Change to YES, no crash
[ queue autorelease ]; // or release, it does not make a difference, in fact leaking the memory makes no difference: the code crashes when the queue is removing the NSOperations
}
每次都会崩溃: bool objc::DenseMapBase >, objc_object*, unsigned long, objc::DenseMapInfo, true>: (EXC_BAD_ACCESS)
完整的堆栈是:
#0 0x9104d81b in objc::DenseMapBase<objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*> >, objc_object*, unsigned long, objc::DenseMapInfo<objc_object*>, true>::find(objc_object* const&) ()
#1 0x910384e3 in _objc_rootReleaseWasZero ()
#2 0x9104d5d9 in -[NSObject release] ()
#3 0x99e41224 in CFRelease ()
#4 0x99e56277 in -[__NSArrayM dealloc] ()
#5 0x9104d5ef in -[NSObject release] ()
#6 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#7 0x9104d5ef in -[NSObject release] ()
#8 0x97f62ac8 in -[NSOperation dealloc] ()
#9 0x9104d5ef in -[NSObject release] ()
#10 0x99e41224 in CFRelease ()
#11 0x99e56277 in -[__NSArrayM dealloc] ()
#12 0x9104d5ef in -[NSObject release] ()
#13 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#14 0x9104d5ef in -[NSObject release] ()
#15 0x97f62ac8 in -[NSOperation dealloc] ()
#16 0x9104d5ef in -[NSObject release] ()
#17 0x99e41224 in CFRelease ()
#18 0x99e56277 in -[__NSArrayM dealloc] ()
#19 0x9104d5ef in -[NSObject release] ()
#20 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#21 0x9104d5ef in -[NSObject release] ()
#22 0x97f62ac8 in -[NSOperation dealloc] ()
#23 0x9104d5ef in -[NSObject release] ()
#24 0x99e41224 in CFRelease ()
#25 0x99e56277 in -[__NSArrayM dealloc] ()
#26 0x9104d5ef in -[NSObject release] ()
#27 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#28 0x9104d5ef in -[NSObject release] ()
#29 0x97f62ac8 in -[NSOperation dealloc] ()
#30 0x9104d5ef in -[NSObject release] ()
#31 0x99e41224 in CFRelease ()
#32 0x99e56277 in -[__NSArrayM dealloc] ()
#33 0x9104d5ef in -[NSObject release] ()
#34 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#35 0x9104d5ef in -[NSObject release] ()
#36 0x97f62ac8 in -[NSOperation dealloc] ()
#37 0x9104d5ef in -[NSObject release] ()
#38 0x99e41224 in CFRelease ()
#39 0x99e56277 in -[__NSArrayM dealloc] ()
#40 0x9104d5ef in -[NSObject release] ()
#41 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#42 0x9104d5ef in -[NSObject release] ()
#43 0x97f62ac8 in -[NSOperation dealloc] ()
#44 0x9104d5ef in -[NSObject release] ()
#45 0x99e41224 in CFRelease ()
#46 0x99e56277 in -[__NSArrayM dealloc] ()
#47 0x9104d5ef in -[NSObject release] ()
#48 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#49 0x9104d5ef in -[NSObject release] ()
#50 0x97f62ac8 in -[NSOperation dealloc] ()
#10722 0x9104d5ef in -[NSObject release] ()
#10723 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10724 0x9104d5ef in -[NSObject release] ()
#10725 0x97f62ac8 in -[NSOperation dealloc] ()
#10726 0x9104d5ef in -[NSObject release] ()
#10727 0x99e41224 in CFRelease ()
#10728 0x99e56277 in -[__NSArrayM dealloc] ()
#10729 0x9104d5ef in -[NSObject release] ()
#10730 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10731 0x9104d5ef in -[NSObject release] ()
#10732 0x97f62ac8 in -[NSOperation dealloc] ()
#10733 0x9104d5ef in -[NSObject release] ()
#10734 0x99e41224 in CFRelease ()
#10735 0x99e56277 in -[__NSArrayM dealloc] ()
#10736 0x9104d5ef in -[NSObject release] ()
#10737 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10738 0x9104d5ef in -[NSObject release] ()
#10739 0x97f62ac8 in -[NSOperation dealloc] ()
#10740 0x9104d5ef in -[NSObject release] ()
#10741 0x99e41224 in CFRelease ()
#10742 0x99e56277 in -[__NSArrayM dealloc] ()
#10743 0x9104d5ef in -[NSObject release] ()
#10744 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10745 0x9104d5ef in -[NSObject release] ()
#10746 0x97f62ac8 in -[NSOperation dealloc] ()
#10747 0x9104d5ef in -[NSObject release] ()
#10748 0x99e41224 in CFRelease ()
#10749 0x99e56277 in -[__NSArrayM dealloc] ()
#10750 0x9104d5ef in -[NSObject release] ()
#10751 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10752 0x9104d5ef in -[NSObject release] ()
#10753 0x97f62ac8 in -[NSOperation dealloc] ()
#10754 0x9104d5ef in -[NSObject release] ()
#10755 0x99e41224 in CFRelease ()
#10756 0x99e56277 in -[__NSArrayM dealloc] ()
#10757 0x9104d5ef in -[NSObject release] ()
#10758 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10759 0x9104d5ef in -[NSObject release] ()
#10760 0x97f62ac8 in -[NSOperation dealloc] ()
#10761 0x9104d5ef in -[NSObject release] ()
#10762 0x99e41224 in CFRelease ()
#10763 0x99e56277 in -[__NSArrayM dealloc] ()
#10764 0x9104d5ef in -[NSObject release] ()
#10765 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10766 0x9104d5ef in -[NSObject release] ()
#10767 0x97f62ac8 in -[NSOperation dealloc] ()
#10768 0x9104d5ef in -[NSObject release] ()
#10769 0x99e41224 in CFRelease ()
#10770 0x99e56277 in -[__NSArrayM dealloc] ()
#10771 0x9104d5ef in -[NSObject release] ()
#10772 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10773 0x9104d5ef in -[NSObject release] ()
#10774 0x97f62ac8 in -[NSOperation dealloc] ()
#10775 0x9104d5ef in -[NSObject release] ()
#10776 0x99e41224 in CFRelease ()
#10777 0x99e56277 in -[__NSArrayM dealloc] ()
#10778 0x9104d5ef in -[NSObject release] ()
#10779 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10780 0x9104d5ef in -[NSObject release] ()
#10781 0x97f62ac8 in -[NSOperation dealloc] ()
#10782 0x9104d5ef in -[NSObject release] ()
#10783 0x99e41224 in CFRelease ()
#10784 0x99e56277 in -[__NSArrayM dealloc] ()
#10785 0x9104d5ef in -[NSObject release] ()
#10786 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10787 0x9104d5ef in -[NSObject release] ()
#10788 0x97f62ac8 in -[NSOperation dealloc] ()
#10789 0x9104d5ef in -[NSObject release] ()
#10790 0x99e41224 in CFRelease ()
#10791 0x99e56277 in -[__NSArrayM dealloc] ()
#10792 0x9104d5ef in -[NSObject release] ()
#10793 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10794 0x9104d5ef in -[NSObject release] ()
#10795 0x97f62ac8 in -[NSOperation dealloc] ()
#10796 0x9104d5ef in -[NSObject release] ()
#10797 0x99e41224 in CFRelease ()
#10798 0x99e56277 in -[__NSArrayM dealloc] ()
#10799 0x9104d5ef in -[NSObject release] ()
#10800 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10801 0x9104d5ef in -[NSObject release] ()
#10802 0x97f62ac8 in -[NSOperation dealloc] ()
#10803 0x9104d5ef in -[NSObject release] ()
#10804 0x99e41224 in CFRelease ()
#10805 0x99e56277 in -[__NSArrayM dealloc] ()
#10806 0x9104d5ef in -[NSObject release] ()
#10807 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10808 0x9104d5ef in -[NSObject release] ()
#10809 0x97f62ac8 in -[NSOperation dealloc] ()
#10810 0x9104d5ef in -[NSObject release] ()
#10811 0x99e41224 in CFRelease ()
#10812 0x99e56277 in -[__NSArrayM dealloc] ()
#10813 0x9104d5ef in -[NSObject release] ()
#10814 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10815 0x9104d5ef in -[NSObject release] ()
#10816 0x97f62ac8 in -[NSOperation dealloc] ()
#10817 0x9104d5ef in -[NSObject release] ()
#10818 0x99e41224 in CFRelease ()
#10819 0x99e56277 in -[__NSArrayM dealloc] ()
#10820 0x9104d5ef in -[NSObject release] ()
#10821 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10822 0x9104d5ef in -[NSObject release] ()
#10823 0x97f62ac8 in -[NSOperation dealloc] ()
#10824 0x9104d5ef in -[NSObject release] ()
#10825 0x99e41224 in CFRelease ()
#10826 0x99e56277 in -[__NSArrayM dealloc] ()
#10827 0x9104d5ef in -[NSObject release] ()
#10828 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10829 0x9104d5ef in -[NSObject release] ()
#10830 0x97f62ac8 in -[NSOperation dealloc] ()
#10831 0x9104d5ef in -[NSObject release] ()
#10832 0x99e41224 in CFRelease ()
#10833 0x99e56277 in -[__NSArrayM dealloc] ()
#10834 0x9104d5ef in -[NSObject release] ()
#10835 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10836 0x9104d5ef in -[NSObject release] ()
#10837 0x97f62ac8 in -[NSOperation dealloc] ()
#10838 0x9104d5ef in -[NSObject release] ()
#10839 0x99e41224 in CFRelease ()
#10840 0x99e56277 in -[__NSArrayM dealloc] ()
#10841 0x9104d5ef in -[NSObject release] ()
#10842 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10843 0x9104d5ef in -[NSObject release] ()
#10844 0x97f62ac8 in -[NSOperation dealloc] ()
#10845 0x9104d5ef in -[NSObject release] ()
#10846 0x99e41224 in CFRelease ()
#10847 0x99e56277 in -[__NSArrayM dealloc] ()
#10848 0x9104d5ef in -[NSObject release] ()
#10849 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10850 0x9104d5ef in -[NSObject release] ()
#10851 0x97f62ac8 in -[NSOperation dealloc] ()
#10852 0x9104d5ef in -[NSObject release] ()
#10853 0x99e41224 in CFRelease ()
#10854 0x99e56277 in -[__NSArrayM dealloc] ()
#10855 0x9104d5ef in -[NSObject release] ()
#10856 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10857 0x9104d5ef in -[NSObject release] ()
#10858 0x97f62ac8 in -[NSOperation dealloc] ()
#10859 0x9104d5ef in -[NSObject release] ()
#10860 0x99e41224 in CFRelease ()
#10861 0x99e56277 in -[__NSArrayM dealloc] ()
#10862 0x9104d5ef in -[NSObject release] ()
#10863 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10864 0x9104d5ef in -[NSObject release] ()
#10865 0x97f62ac8 in -[NSOperation dealloc] ()
#10866 0x9104d5ef in -[NSObject release] ()
#10867 0x99e41224 in CFRelease ()
#10868 0x99e56277 in -[__NSArrayM dealloc] ()
#10869 0x9104d5ef in -[NSObject release] ()
#10870 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10871 0x9104d5ef in -[NSObject release] ()
#10872 0x97f62ac8 in -[NSOperation dealloc] ()
#10873 0x9104d5ef in -[NSObject release] ()
#10874 0x99e41224 in CFRelease ()
#10875 0x99e56277 in -[__NSArrayM dealloc] ()
#10876 0x9104d5ef in -[NSObject release] ()
#10877 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10878 0x9104d5ef in -[NSObject release] ()
#10879 0x97f62ac8 in -[NSOperation dealloc] ()
#10880 0x9104d5ef in -[NSObject release] ()
#10881 0x99e41224 in CFRelease ()
#10882 0x99e56277 in -[__NSArrayM dealloc] ()
#10883 0x9104d5ef in -[NSObject release] ()
#10884 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10885 0x9104d5ef in -[NSObject release] ()
#10886 0x97f62ac8 in -[NSOperation dealloc] ()
#10887 0x9104d5ef in -[NSObject release] ()
#10888 0x99e41224 in CFRelease ()
#10889 0x99e56277 in -[__NSArrayM dealloc] ()
#10890 0x9104d5ef in -[NSObject release] ()
#10891 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10892 0x9104d5ef in -[NSObject release] ()
#10893 0x97f62ac8 in -[NSOperation dealloc] ()
#10894 0x9104d5ef in -[NSObject release] ()
#10895 0x99e41224 in CFRelease ()
#10896 0x99e56277 in -[__NSArrayM dealloc] ()
#10897 0x9104d5ef in -[NSObject release] ()
#10898 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10899 0x9104d5ef in -[NSObject release] ()
#10900 0x97f62ac8 in -[NSOperation dealloc] ()
#10901 0x9104d5ef in -[NSObject release] ()
#10902 0x99e41224 in CFRelease ()
#10903 0x99e56277 in -[__NSArrayM dealloc] ()
#10904 0x9104d5ef in -[NSObject release] ()
#10905 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10906 0x9104d5ef in -[NSObject release] ()
#10907 0x97f62ac8 in -[NSOperation dealloc] ()
#10908 0x9104d5ef in -[NSObject release] ()
#10909 0x99e41224 in CFRelease ()
#10910 0x99e56277 in -[__NSArrayM dealloc] ()
#10911 0x9104d5ef in -[NSObject release] ()
#10912 0x97f62b22 in -[__NSOperationInternal dealloc] ()
#10913 0x9104d5ef in -[NSObject release] ()
#10914 0x97f62ac8 in -[NSOperation dealloc] ()
#10915 0x9104d5ef in -[NSObject release] ()
#10916 0x97f49cca in __NSOQSchedule_f ()
#10917 0x9c1c9e21 in _dispatch_async_redirect_invoke ()
#10918 0x9c1c53a6 in _dispatch_client_callout ()
#10919 0x9c1c7467 in _dispatch_root_queue_drain ()
#10920 0x9c1c8732 in _dispatch_worker_thread2 ()
#10921 0x960c2dab in _pthread_wqthread ()
完整的崩溃上下文是(粗体表示崩溃行):
libobjc.A.dylib`objc::DenseMapBase<objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*> >, objc_object*, unsigned long, objc::DenseMapInfo<objc_object*>, true>::find(objc_object* const&):
0x9104d800: pushl %ebp
0x9104d801: movl %esp, %ebp
0x9104d803: pushl %esi
0x9104d804: subl $20, %esp
0x9104d807: leal -8(%ebp), %eax
0x9104d80a: movl %eax, 8(%esp)
0x9104d80e: movl 16(%ebp), %eax
0x9104d811: movl %eax, 4(%esp)
0x9104d815: movl 12(%ebp), %esi
0x9104d818: movl %esi, (%esp)
**0x9104d81b: calll 0x9104d9b6 ; bool objc::DenseMapBase<objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*> >, objc_object*, unsigned long, objc::DenseMapInfo<objc_object*>, true>::LookupBucketFor<objc_object*>(objc_object* const&, std::__1::pair<objc_object*, unsigned long> const*&) const**
0x9104d820: movl 12(%esi), %ecx
0x9104d823: shll $3, %ecx
0x9104d826: addl (%esi), %ecx
0x9104d828: movl 8(%ebp), %edx
0x9104d82b: testb %al, %al
0x9104d82d: je 0x9104d836 ; objc::DenseMapBase<objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*> >, objc_object*, unsigned long, objc::DenseMapInfo<objc_object*>, true>::find(objc_object* const&) + 54
0x9104d82f: movl -8(%ebp), %eax
0x9104d832: movl %eax, (%edx)
0x9104d834: jmp 0x9104d838 ; objc::DenseMapBase<objc::DenseMap<objc_object*, unsigned long, true, objc::DenseMapInfo<objc_object*> >, objc_object*, unsigned long, objc::DenseMapInfo<objc_object*>, true>::find(objc_object* const&) + 56
0x9104d836: movl %ecx, (%edx)
0x9104d838: movl %ecx, 4(%edx)
0x9104d83b: addl $20, %esp
0x9104d83e: popl %esi
0x9104d83f: popl %ebp
0x9104d840: ret $4
0x9104d843: nop
我尝试使用预先创建的队列,这没有区别。显然,由于依赖关系,这段代码是 XCode 5.0 32 位的问题。
编辑:事实上,我可以进一步隔离问题。XCOde 5.0 在 10.9 上的一个空的 Cocoa 应用程序项目在 ARC 和单个方法上会崩溃。如果它不在您的计算机上,请将 4269 增加到更大的值:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSOperationQueue* aQueue = [[ NSOperationQueue alloc ] init ];
NSMutableArray* array = [ NSMutableArray array ];
for ( int i = 0; i < 4269; i++)
[ array addObject: [ [NSOperation alloc ] init ]];
for ( int i = 1; i < [ array count ]; i++)
[[ array objectAtIndex:i ] addDependency:[array objectAtIndex:i-1]];
[ aQueue addOperations: array waitUntilFinished:NO ];
}
编辑2:
请注意,以下代码将在一个干净的新项目中崩溃(ARC ON,但我认为这无关紧要)。我希望队列保持强引用(保留)NSOperation。
- NSOperationQueue 被永久保存,永远不会被释放。
- 没有临时的 NSMutableArray。
- 操作一添加就开始运行
这是代码:
static NSOperationQueue* aQueue = nil;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
aQueue = [[ NSOperationQueue alloc ] init ];
NSOperation* lastOp = nil;
for ( int i = 0; i < 5000 ; i++) {
NSOperation* newOp = [ NSBlockOperation blockOperationWithBlock:^{ ;} ];
if ( lastOp != nil )
[ newOp addDependency: lastOp ];
[ aQueue addOperation:newOp ];
lastOp = newOp;
}
}