调试过度释放的对象,NSZombie的问题

时间:2011-01-31 06:18:45

标签: objective-c xcode debugging nszombie

编辑:我找到了这次崩溃的原因! bbum指出缓冲区溢出是一个非常常见的原因,所以我查看了我唯一的缓冲区类型malloc:

closedList = (AINavigationCell **)malloc(baseCells.count * sizeof(AINavigationCell *));

我后来覆盖了数据超出数组范围的数据,这应该比baseCells.count大得多。谢谢bbum!

问题: 我在EXC_BAD_ACCESS -drain期间有一个可重现的NSAutoreleasePool,这似乎表明我过度释放了一个对象。所以我启用NSZombie,但程序不再崩溃。我也没有将任何信息记录到控制台。如果我关闭NSZombie,崩溃就会恢复。这是什么意思?我以为NSZombies习惯于解决这类问题。如果NSZombie无法帮助,是否有另一种方法可以查询这个过度释放的对象?

此外,在Simulator上无法重现崩溃,这就是为什么我不能将仪器与NSZombie一起使用。

Folowing是崩溃时的回溯。

#0  0x31ac8bc8 in _cache_fill ()
#1  0x31acaf8e in lookUpMethod ()
#2  0x31ac8780 in _class_lookupMethodAndLoadCache ()
#3  0x31ac859a in objc_msgSendSuper_uncached ()
#4  0x328014f0 in -[__NSArrayReverseEnumerator dealloc] ()
#5  0x327b1f7a in -[NSObject(NSObject) release] ()
#6  0x327b63c8 in CFRelease ()
#7  0x327b58de in _CFAutoreleasePoolPop ()
#8  0x320e132c in NSPopAutoreleasePool ()
#9  0x30899048 in CAPopAutoreleasePool ()
#10 0x30902784 in CA::Display::DisplayLink::dispatch ()
#11 0x309027ea in CA::Display::IOMFBDisplayLink::callback ()
#12 0x30076bfa in IOMobileFramebufferVsyncNotifyFunc ()
#13 0x333dee6a in IODispatchCalloutFromCFMessage ()
#14 0x327e8be6 in __CFMachPortPerform ()
#15 0x327e06fe in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#16 0x327e06c2 in __CFRunLoopDoSource1 ()
#17 0x327d2f7c in __CFRunLoopRun ()
#18 0x327d2c86 in CFRunLoopRunSpecific ()
#19 0x327d2b8e in CFRunLoopRunInMode ()
#20 0x3094a4aa in GSEventRunModal ()
#21 0x3094a556 in GSEventRun ()
#22 0x32c14328 in -[UIApplication _run] ()
#23 0x32c11e92 in UIApplicationMain ()
#24 0x00002556 in main (argc=1, argv=0x2fdff660) at /Users/hyn/Desktop/MyProject-trunk/main.m:14

1 个答案:

答案 0 :(得分:16)

您描述的问题可能是以下几个问题之一;你可能过度释放一个物体,或者你可能会破坏记忆。如果你破坏了内存 - 特别是破坏了对象的前几个字节 - 那么在自动释放池排放(或任何其他消息)期间它很容易表现为崩溃。

崩溃发生在设备上,而不是模拟器,也指向内存损坏。设备[ARM]与模拟器[i386]的体系结构完全不同,可能存在许多问题。

通常情况下,它并没有如此一致地表现出来。

首先,发布崩溃的回溯。这可能有所帮助。

其次,你做过任何原始的malloc电话吗?或者用数据填充缓冲区?这种崩溃的最常见原因是在缓冲区结束时运行。


#0  0x31ac8bc8 in _cache_fill ()
#1  0x31acaf8e in lookUpMethod ()
#2  0x31ac8780 in _class_lookupMethodAndLoadCache ()
#3  0x31ac859a in objc_msgSendSuper_uncached ()
#4  0x328014f0 in -[__NSArrayReverseEnumerator dealloc] ()

(以上是在OP修复问题后添加的,但是 - 对于存档而言)

崩溃跟踪是内存损坏的经典签名。也就是说,isa指针 - 一个指向实例类的对象中第一个指针的字节值 - 被踩踏。当您在对象之前超出分配中的内存缓冲区时,通常会发生这种情况。如果它只是几个字节溢出,那么不同平台之间的行为可能会有所不同,因为malloc量子 - 分配的实际大小(你在一个平台上要求90个字节,你可能得到96个。另一个?128) - - 平台之间甚至是版本之间存在差异。

特别是,isa被重写了一个看起来像指针的值,运行时取消引用了垃圾值,然后尝试将结果位置视为Class的方法表。

任何时候你看到一个objc_msgSend*()函数之一深度的崩溃,很可能是内存损坏,如果是这样,它几乎总是缓冲区溢出。

由于这很容易做到,所以使用僵尸检测进行测试通过以捕获“有时它实际上只是一个过度释放的情况”仍然是一个好主意。