了解EXC_BAD_ACCESS(SIGSEGV)崩溃的解决方案

时间:2014-03-20 07:40:24

标签: ios objective-c

我已经调试了一天左右的iOS应用程序,尝试解决EXC_BAD_ACCESS(SIGSEGV)崩溃问题。

这是崩溃日志中有趣的部分:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000051
Triggered by Thread:  0

Thread 0 Crashed:
0   libsystem_kernel.dylib          0x38bfc6e4 __kill + 8
1   myApp                           0x002e3ca0 CLSSignalHandler + 192
2   libsystem_platform.dylib        0x38c61060 _sigtramp + 40
3   UIKit                           0x306416a2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 310
4   UIKit                           0x306417d0 __85-[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]_block_invoke + 104
5   UIKit                           0x306416e2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 374
6   UIKit                           0x30641af2 -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:] + 30
7   UIKit                           0x308d84b8 __UIViewWasRemovedFromSuperview + 184
8   UIKit                           0x30640bae -[UIView(Hierarchy) removeFromSuperview] + 266
9   UIKit                           0x30643402 -[UIView dealloc] + 362
10  CoreFoundation                  0x2de00650 CFRelease + 552
11  CoreFoundation                  0x2de0bb40 -[__NSArrayM dealloc] + 152
12  libobjc.A.dylib                 0x38649b06 objc_object::sidetable_release(bool) + 170
13  libobjc.A.dylib                 0x3863b002 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 354
14  CoreFoundation                  0x2de0397c _CFAutoreleasePoolPop + 12
15  UIKit                           0x3063b248 _wrapRunLoopWithAutoreleasePoolHandler + 32
16  CoreFoundation                  0x2de9b1ca __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18
17  CoreFoundation                  0x2de98b6c __CFRunLoopDoObservers + 280
18  CoreFoundation                  0x2de98eae __CFRunLoopRun + 726
19  CoreFoundation                  0x2de03c22 CFRunLoopRunSpecific + 518
20  CoreFoundation                  0x2de03a06 CFRunLoopRunInMode + 102
21  GraphicsServices                0x32af727e GSEventRunModal + 134
22  UIKit                           0x306a7044 UIApplicationMain + 1132
23  myApp                           0x000c4640 main (main.m:14)
24  myApp                           0x000ac31c start + 36

不幸的是,NSZombieEnabled没有用,因为在设置崩溃时崩溃不再发生。

从我的研究中我发现:

  • 它可能来自一个被释放的对象两次(在日志中存在Release和AutoRelease的东西)
  • NSZombie对象在收到release消息时不记录任何内容

在将问题的根源缩小到1级之后,我查看了变量和属性的分配和释放。我在viewDidLoad中找到了这个:

MyView *view = [[MyView alloc] initWithFrame:CGRectMake(...)];
[_tableView addSubview:view]; // _tableView is an outlet variable
_refreshHeaderView = view; // _refreshHeaderView is a class variable, not a property
[view release];

viewDidUnload

[_refreshHeaderView release];
_refreshHeaderView = nil;

我将_refreshHeaderView = view;更改为_refreshHeaderView = [view retain];,现在应用程序不再崩溃。

我不太确定这是正确的解决方案,虽然崩溃不再发生,所以我有这些问题的原因:

  1. 我对发生的事情的理解是:
    • view已初始化,其RC = 1
    • view被添加为_tableView RC = 2
    • 的子视图
    • _refreshHeaderView指向与view
    • 相同的对象
    • view已发布RC = 1
    • 当dealloc进程开始时,_tableView将释放view RC = 0
    • 发布_refreshHeaderView时,应用程序崩溃
    • 这是对的吗?
  2. 为什么崩溃日志会显示自动释放内容,尽管它不会与我的变量一起使用?
  3. NSZombies收到发布消息时是否记录任何错误是真的吗?
  4. 哪一个更好?
    • _refreshHeaderView = [view retain];[_refreshHeaderView release];
    • _refreshHeaderView = view; [_refreshHeaderView release];
  5. 感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

第1点的摘要对我来说是正确的。

不要将AutoReleasePools与ARC混淆 - AutoReleasePools就像Java中的垃圾收集器。如果需要,可以显式创建AutoReleasePool,但始终使用运行循环建立隐式池。迁移到ARC可能需要更改代码(并且需要不同地使用AutoRelease)。

有关NSZombies的信息在this answer。基本上你应该得到一个日志,如果你发布一个参考数为0的NSZombie。我不知道为什么你没有看到警告。

_refreshHeaderView = [view retain]; and [_refreshHeaderView release];更好,因为您的对象持有对象的引用,因此需要管理引用计数。