【问题标题】:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_disposedispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)
【发布时间】:2014-08-11 19:59:02
【问题描述】:

我在 dispatch_semaphore_dispose 上收到 EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 但我真的不知道如何追查其根本原因。我的代码使用了 dispatch_async、dispatch_group_enter 等等。

更新: 崩溃的原因是由于 webserviceCall(见下面的代码)从不调用 onCompletion 并且当代码再次运行时,我收到错误 EXC_BAD_INSTRUCTION。我证实确实如此,但不知道为什么或如何防止这种情况。

代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();

     for (...) {
        if (...) {
            dispatch_group_enter(group);
            dispatch_async(queue, ^{

               [self webserviceCall:url onCompletion:^{
                     dispatch_group_leave(group);
               }];
            });
        }
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
    dispatch_sync(queue, ^{
        // call completion handler passed in by caller
    });
});

【问题讨论】:

  • 不是重复的。我看了看,对我没有帮助。注意我的也是 EXC_I386_INVOP。
  • 这可能是 ARC 问题。发布您对调度组、信号量或 dispatch_sync 所做的任何事情。 ARC 可能正在尝试处理已设置为 NULL 的信号量。
  • 为了在块内使用weakSelf。
  • FYI 1. 如果您创建了一个由您自己编写的fatalError/assertionFailure,您将收到一个错误EXC_BAD_INSTRUCTION。因此你应该明白为什么你已经达到了你自己的断言,即查看它的信息。话虽如此,这个错误是由编译器产生的。 2. 我的观点是编译器也使用fatalError,我们看到的许多错误都是因为这个

标签: ios objective-c exception grand-central-dispatch


【解决方案1】:

从您的堆栈跟踪中,EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 发生是因为 dispatch_group_t 在仍处于锁定状态(等待 dispatch_group_leave)时被释放

根据你的发现,事情是这样的:

  • dispatch_group_t group 已创建。 group 的保留计数 = 1。
  • -[self webservice:onCompletion:] 捕获了groupgroup 的保留计数 = 2。
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... }); 再次捕获了groupgroup 的保留计数 = 3。
  • 退出当前范围。 group 已发布。 group 的保留计数 = 2。
  • dispatch_group_leave 从未被调用过。
  • dispatch_group_wait 超时。 dispatch_async 块已完成。 group 已发布。 group 的保留计数 = 1。
  • 您再次调用了此方法。当再次调用-[self webservice:onCompletion:] 时,旧的onCompletion 块被替换为新的块。所以,旧的group 被释放了。 group 的保留计数 = 0。 group 已被释放。结果是EXC_BAD_INSTRUCTION

要解决这个问题,我建议你应该找出-[self webservice:onCompletion:] 没有调用onCompletion 阻止的原因,并修复它。然后确保对方法的下一次调用将在上一次调用完成之后发生。


如果您允许该方法被多次调用,无论之前的调用是否完成,您可能会找人为您保留group

  • 您可以将超时时间从 2 秒更改为 DISPATCH_TIME_FOREVER 或所有 -[self webservice:onCompletion] 应该调用其 onCompletion 块的合理时间量。这样dispatch_async(...) 中的块就会为您保存它。
    或者
  • 您可以将group 添加到集合中,例如NSMutableArray

我认为这是为此操作创建专用类的最佳方法。当你想调用 webservice 时,你创建一个类的对象,调用它的方法,完成块传递给它,释放对象。在类中,有一个dispatch_group_tdispatch_semaphore_t 的ivar。

【讨论】:

  • 哇,惊人的分析。如果我将组添加到集合中,它永远不会被释放,对吧?我可能无法修复不返回的 web 服务,因为这是一个框架,我不能阻止其他人创建不返回的 web 服务调用(错误地),我想确保我的框架不会崩溃那些情况。
  • 是的,所以你必须在使用完后将其从集合中移除。
  • 这个答案对我帮助很大。非常感谢!就我而言,我只在 onCompletion 中调用了 dispatch_group_leave,但在 onCancellation 中忘记了调用它。在任何情况下调用 dispatch_group_leave 都可以解决我的问题。
  • 帮了我大忙,我宣布了一个ivar调度组,但没有进出比较。
  • 对我来说这很奇怪,我有 2 个参数错误地具有相同的名称,并且在运行时出现此错误。
【解决方案2】:

我的问题是我正在创建想要存储在 NSMutableDictionary 中的对象,但我从未初始化字典。因此,对象被垃圾收集删除并在以后破坏。检查您是否对正在与之交互的对象至少有一个强引用。

【讨论】:

    【解决方案3】:

    就我而言:

    PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
    requestOptions.synchronous            = NO;
    

    试图用 dispatch_group 来做这个

    【讨论】:

      【解决方案4】:

      我的问题是IBOutlet,但没有连接到界面生成器并在 swift 文件中使用。

      【讨论】:

      • 我也有同样的问题。我们能否从错误消息中找出哪些 IBOutlet 可以取消链接?
      • 如果该类只有一个 1 InterfaceBuilder,那么您可以检查 .swift 或 .m / .h 文件中的每个 IBOutlet 连接或断开符号。
      • 有同样的问题,是从一个按钮引用一个动作而不将按钮本身添加为 IBOutlet。
      【解决方案5】:

      我有一个不同的问题让我想到了这个问题,这可能比已接受答案中的过度发布问题更常见。

      根本原因是我们的完成块被调用两次,因为网络处理程序中的 if/else 失败,导致每次调用 dispatch_group_enter 都会调用两次 dispatch_group_leave。 p>

      完成块被多次调用:

      dispatch_group_enter(group);
      [self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) {
      
          // this block is called multiple times
          // one `enter` but multiple `leave`
      
          dispatch_group_leave(group);
      }];
      

      通过 dispatch_group 的 count 调试

      EXC_BAD_INSTRUCTION 上,您应该仍然可以在调试器中访问您的 dispatch_group。 DispatchGroup: check how many "entered"

      打印出 dispatch_group 你会看到:

      <OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>

      当您看到count = -1 时,表明您已经过度离开了 dispatch_group。请务必将dispatch_enterdispatch_leave 分组配对。

      【讨论】:

      • 关于count = -1 的提示非常有帮助 - 谢谢!
      • 我遇到了类似的情况-尽管在完成块中使用了 group=DispatchGroup() 和 group.enter() 以及相应的 group.leave() (被多次调用)。在调试器中,组的计数是 1073741823——作为有符号的 32 位 int 也是 -1
      【解决方案6】:

      我来到这里是因为一个 XCTestCase,我在其中禁用了大多数测试,方法是在 no_testBackgroundAdding 中添加“no_”作为前缀。一旦我注意到大多数答案都与锁和线程有关,我意识到测试包含一些 XCTestExpectation 实例和相应的 waitForExpectations。它们都在禁用测试中,但显然 Xcode 仍在某种程度上评估它们。

      最后我找到了一个定义为@property 但缺少@synthesize 的XCTestExpectation。一旦我添加了综合指令,EXC_BAD_INSTRUCTION 就消失了。

      【讨论】:

        【解决方案7】:

        有时获得EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 所需要的只是缺少return 语句。

        这当然是我的情况。

        【讨论】:

          【解决方案8】:

          我的问题是它在我的 init() 中。 可能是“弱自我”在初始化尚未完成时杀死了他。 我将它从 init 中移出,它解决了我的问题。

          【讨论】:

            猜你喜欢
            • 2012-05-30
            • 2016-02-19
            • 1970-01-01
            • 2016-08-08
            • 1970-01-01
            • 1970-01-01
            • 2018-06-16
            • 1970-01-01
            相关资源
            最近更新 更多