GCD dispatch_after调用引起SIGBUS信号

我正在使用GCD的dispatch_after方法,当我的应用程序被加载执行一些行为。 预期的行为是从applicationDidFinishLaunchingWithOptions结束等待3秒,以执行在后台队列中运行的select器。

我的testing设备上没有遇到任何崩溃,但是我有用户崩溃报告了未捕获的SIGBUS信号,原因是BUS_ADRALNexception。 从我对此代码的理解中,BUS_ADRALN错误表示地址alignment错误。

这是我如何创build我的计时器:

 double delayInSeconds = 3.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){ [self methodToPerformInBackground]; }); 

什么可能导致这次崩溃?

因为multithreading错误可能是一种奇怪的东西,所以我会抛出一些我一直在脑海中徘徊的想法。

  • 我打电话给[self performSelectorOnMainThread:withObject:waitUntilDone] 。 在这样的select器中做这个问题有什么问题吗?
  • 由于我打电话dispatch_get_global_queue而不是dispatch_create_queue ,我不需要保留这个方法返回的队列。 这个推理是否正确?
  • 在这个代码中, self是应用程序委托。 在应用程序进入后台或终止之后,是否可能导致崩溃? 应用程序在closures时是否自动清理所有调度的块?
  • 被调用方法内部的东西导致崩溃,但GCD不提供堆栈跟踪。

编辑:我宁愿不包括块中调用的代码,因为我不相信这是主要的问题。 这是堆栈跟踪。 线程0上的崩溃使得仿佛问题出现在GCD中,而不是块中调用的代码。

编辑#2:通过更多的崩溃报告,我有奇怪的消息分享。 此崩溃只出现在运行iOS 4.2.X及更低版本的用户上。 由于iOS 4.0及更高版本支持GCD,因此我的猜测是在4.3中修正了一个bug。

 Thread 0 Crashed: 0 libSystem.B.dylib 0x35e5fb10 _dispatch_retain + 0 1 libSystem.B.dylib 0x35e5df8c dispatch_after_f + 80 2 libSystem.B.dylib 0x35e5e070 dispatch_after + 72 3 MyApplication 0x0000466c -[MyApplicationDelegate applicationDidFinishLaunchingPart2:] (MyApplicationDelegate.m:366) 4 CoreFoundation 0x37538f79 -[NSObject(NSObject) performSelector:withObject:] + 25 5 Foundation 0x35171e6d __NSThreadPerformPerform + 273 6 CoreFoundation 0x375518d1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 7 CoreFoundation 0x37521ecd __CFRunLoopDoSources0 + 385 8 CoreFoundation 0x375216f9 __CFRunLoopRun + 265 9 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227 10 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61 11 GraphicsServices 0x33e76d24 GSEventRunModal + 196 12 UIKit 0x3591d57c -[UIApplication _run] + 588 13 UIKit 0x3591a558 UIApplicationMain + 972 14 MyApplication 0x00003024 main (main.m:113) Thread 1: 0 libSystem.B.dylib 0x35d8f974 kevent + 24 1 libSystem.B.dylib 0x35e5dd70 _dispatch_queue_invoke + 104 2 libSystem.B.dylib 0x35e5d790 _dispatch_worker_thread2 + 128 3 libSystem.B.dylib 0x35de6978 _pthread_wqthread + 400 Thread 2: 0 libSystem.B.dylib 0x35de72fc __workq_kernreturn + 8 Thread 3: 0 libSystem.B.dylib 0x35d5b3b0 mach_msg_trap + 20 1 CoreFoundation 0x37521f83 __CFRunLoopServiceMachPort + 95 2 CoreFoundation 0x37521787 __CFRunLoopRun + 407 3 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227 4 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61 5 WebCore 0x3318bd1c _ZL12RunWebThreadPv + 532 6 libSystem.B.dylib 0x35de5b4c _pthread_start + 372 Thread 4: 0 libSystem.B.dylib 0x35d5b3b0 mach_msg_trap + 20 1 CoreFoundation 0x37521f83 __CFRunLoopServiceMachPort + 95 2 CoreFoundation 0x37521787 __CFRunLoopRun + 407 3 CoreFoundation 0x3752150b CFRunLoopRunSpecific + 227 4 CoreFoundation 0x37521419 CFRunLoopRunInMode + 61 5 Foundation 0x3517ec55 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 217 6 Foundation 0x3515cb91 -[NSThread main] + 49 7 Foundation 0x35155b97 __NSThread__main__ + 915 8 libSystem.B.dylib 0x35de5b4c _pthread_start + 372 

DISPATCH_QUEUE_PRIORITY_BACKGROUND是iOS 5.0+特性。 如果您尝试在iOS 4.x上使用它,它将是NULL(当您尝试保留它时会崩溃,因为GCD是一个C库,并且使用NULL的方式是不安全的, -C)。 看到这个答案更多的信息。 解决scheme是使用低优先级,或使用预处理器指令在两者之间切换。