dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)
Posted
技术标签:
【中文标题】dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)【英文标题】:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose 【发布时间】: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
,我们看到的许多错误都是因为这个
【参考方案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:]
捕获了group
。 group
的保留计数 = 2。
dispatch_async(...., ^ dispatch_group_wait(group, ...) ... );
再次捕获了group
。 group
的保留计数 = 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
:
DISPATCH_TIME_FOREVER
或所有 -[self webservice:onCompletion]
应该调用其 onCompletion
块的合理时间量。这样dispatch_async(...)
中的块就会为您保存它。
或者
您可以将group
添加到集合中,例如NSMutableArray
。
我认为这是为此操作创建专用类的最佳方法。当你想调用 webservice 时,你创建一个类的对象,调用它的方法,完成块传递给它,释放对象。在类中,有一个dispatch_group_t
或dispatch_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_enter
和dispatch_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 中移出,它解决了我的问题。
【讨论】:
以上是关于dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)的主要内容,如果未能解决你的问题,请参考以下文章