iOS 崩溃 - 在当前参数寄存器中找到的选择器名称:保留
iOS crash - Selector name found in current argument registers: retain
在曲棍球应用仪表板中,我遇到崩溃并提示以下内容:
异常类型:SIGTRAP
异常代码:#0 在 0x1943f61e8
崩溃线程:7
应用程序特定信息:
在当前参数寄存器中找到的选择器名称:retain
异常类型:SIGSEGV
异常代码:SEGV_ACCERR 在 0x568855a90
崩溃线程:18
应用程序特定信息:
objc_msgSend() 选择器名称:保留
两个崩溃组都遇到了相同的代码,但不知何故他们有不同的崩溃描述,我认为这应该是相同的根本原因。
这是我的代码的样子:
线程 1:
dispatch_queue_t queue;
@synchronized (self) {
queue = _mySerialQueue;
}
dispatch_async(queue, ^{ // Crash happens here
if (_ivar) {
...
}
});
线程 2:
@synchronized (self) {
_mySerialQueue = dispatch_queue_create(...);
}
这段代码可以运行成ARC问题吗?
前提是(请验证这些)
_mySerialQueue
是实例变量
_mySerialQueue
仅在 @synchronized(self)
个块内访问
- 您不通过任何 属性 或键值编码 (
[theObject valueForKey:"mySerialQueue"]
) 访问 _mySerialQueue
- 您发布的所有代码都使用 ARC 运行
我只看到上述代码崩溃的原因之一。我仍然不是 100% 确定,但这是我的镜头:
当崩溃发生时,self
正在被释放。如果在dealloc
:
清理iVar可以检查
- (void)dealloc {
@synchronized(self) {
_mySerialQueue = nil;
}
// ...
}
这些崩溃极其罕见,例如至少百分之一。如果经常出现,我认为是其他地方的问题。
更改后,应用程序仍会崩溃,但 EXC_BAD_ACCESS 将位于较低的内存位置,因为您在调用 dispatch_async(nil, ...)
时取消引用 NULL 指针。崩溃位置很可能是 0x00000050,或者类似的低地址。
为什么我会这样想?
当一个对象被销毁时,iVars 在一个单独的通道中被名为 .cxx_destruct
的方法销毁。当发生这种情况时,iVar 可能处于被释放的过程中,但同时变量仍然指向该对象,因为它从未被清除。
重要提示:如果这有效,它只会用另一个罕见的崩溃替换一个罕见的崩溃,因为这意味着 self
某处存在竞争条件.
另一种可能的解决方案是尝试使用 thread sanitizer 重现该问题。在大多数情况下,它可以非常快速地跟踪此类问题。
在曲棍球应用仪表板中,我遇到崩溃并提示以下内容:
异常类型:SIGTRAP 异常代码:#0 在 0x1943f61e8 崩溃线程:7 应用程序特定信息: 在当前参数寄存器中找到的选择器名称:retain
异常类型:SIGSEGV 异常代码:SEGV_ACCERR 在 0x568855a90 崩溃线程:18 应用程序特定信息: objc_msgSend() 选择器名称:保留
两个崩溃组都遇到了相同的代码,但不知何故他们有不同的崩溃描述,我认为这应该是相同的根本原因。
这是我的代码的样子:
线程 1:
dispatch_queue_t queue;
@synchronized (self) {
queue = _mySerialQueue;
}
dispatch_async(queue, ^{ // Crash happens here
if (_ivar) {
...
}
});
线程 2:
@synchronized (self) {
_mySerialQueue = dispatch_queue_create(...);
}
这段代码可以运行成ARC问题吗?
前提是(请验证这些)
_mySerialQueue
是实例变量_mySerialQueue
仅在@synchronized(self)
个块内访问- 您不通过任何 属性 或键值编码 (
[theObject valueForKey:"mySerialQueue"]
) 访问 - 您发布的所有代码都使用 ARC 运行
_mySerialQueue
我只看到上述代码崩溃的原因之一。我仍然不是 100% 确定,但这是我的镜头:
当崩溃发生时,self
正在被释放。如果在dealloc
:
- (void)dealloc {
@synchronized(self) {
_mySerialQueue = nil;
}
// ...
}
这些崩溃极其罕见,例如至少百分之一。如果经常出现,我认为是其他地方的问题。
更改后,应用程序仍会崩溃,但 EXC_BAD_ACCESS 将位于较低的内存位置,因为您在调用 dispatch_async(nil, ...)
时取消引用 NULL 指针。崩溃位置很可能是 0x00000050,或者类似的低地址。
为什么我会这样想?
当一个对象被销毁时,iVars 在一个单独的通道中被名为 .cxx_destruct
的方法销毁。当发生这种情况时,iVar 可能处于被释放的过程中,但同时变量仍然指向该对象,因为它从未被清除。
重要提示:如果这有效,它只会用另一个罕见的崩溃替换一个罕见的崩溃,因为这意味着 self
某处存在竞争条件.
另一种可能的解决方案是尝试使用 thread sanitizer 重现该问题。在大多数情况下,它可以非常快速地跟踪此类问题。