Nic*_*son 8 objective-c instruments nszombie grand-central-dispatch retaincount
我对偶然发生的碰撞感到困惑,根据Zombies乐器的说法,这是由于一些字典值的过度释放造成的.当我查看Instruments中这些过度释放的对象之一的对象历史时,我发现它的保留计数在一个阶段从+2直接下降到0.(看一下帖子末尾的截图).我不清楚这是怎么可能的.
我应该说在使用Instruments进行分析时我只看到这种崩溃,所以我认为它可能是一个Apple漏洞,但是假设它是导航错误可能更安全,而Instruments只是暴露出来.
无论如何,我正在构建一个包含一些Core Foundation对象(CFStrings和CFNumbers)的CFDictionary,然后我将它转换为NSDictionary*并将其传递给Objective-C方法.我的代码的简化版本如下:
// creates a CFDictionary containing some CFStrings and CFNumbers
void doStuff()
{
CFDictionaryRef myDict = CreateMyDictionaryContainingCFTypes();
dispatch_async(myQueue, ^{
[someObject receiveDictionary:(NSDictionary*)myDict];
CFRelease(myDict); // this line causes a crash. The Zombies instrument
// claims a CFString value contained in this
// dictionary has already been freed.
});
}
// ...
- (void)receiveDictionary:(NSDictionary*)dict
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString* str1 = [dict objectForKey:@"key1"];
NSString* str2 = [dict objectForKey:@"key2"];
NSNumber* num1 = [dict objectForKey:@"key3"];
dispatch_async(myOtherQueue, ^{
[database executeUpdate:@"INSERT INTO blah (x,y,z) VALUES (?, ?, ?)", str1, str2, num1];
});
[pool drain];
}
Run Code Online (Sandbox Code Playgroud)
我曾经想过str1
,str2
并且num1
会被视为Objective-C对象,因此当-receiveDictionary:
通过dispatch_async
调用复制块in时会被捕获并自动保留,并在释放该块时释放.实际上,这些变量确实似乎被块捕获并保留.但是,检查Instruments中过度释放的CFString的对象历史记录,我可以看到在复制块时它的引用计数正在递增.令人困惑的是,当一个块被释放时,它的保留计数从+2直接下降到0(参见帖子末尾的截图); 我不知道如何从堆栈跟踪告诉它是哪个块.当CFRelease
在块中的字典上调用时doStuff()
,它的一些值已经被释放,程序崩溃了.
那么额外的发布电话来自哪里?如仪器所示,对象的保留计数如何从+2直接下降到0?
一时兴起,我强迫第二个块保留整个字典,如下所示:
dispatch_async(myOtherQueue, ^{
[database executeUpdate:@"INSERT INTO blah (x,y,z) VALUES (?, ?, ?)", str1, str2, num1];
[dict self];
});
Run Code Online (Sandbox Code Playgroud)
这似乎使崩溃消失了; 仪器至少停止报告僵尸.我不能为我的生活看到为什么这样有效; 当然我只是为了确保该块保留我感兴趣的字典值,而不是整个字典.发生什么了?
Instruments列出了僵尸CFString的以下对象历史记录,其中包含对象的保留计数.我已经为有趣的事件添加了截图.
#0 +1创建CFString
#1 + 2 CFString添加到字典
#2 + 1 CFString发布
#3 +2 当-receiveDictionary:
复制块时保留CFString
#4 + 0 什么...?对象的保留计数从+2直接下降到0!
#5 -1 CFDictionary被释放,导致崩溃
最终发现了错误 \xe2\x80\x94 ,事实证明这根本不是僵尸问题,而是解码 Base64 数据的例程中不相关的内存损坏问题。与保留/释放、块或 GCD 无关。叹。
\n\n事后看来,这一点应该更加明显。事实上,在 Instruments 报告过度释放的对象后不久,我的程序就崩溃了,这应该是一个线索 \xe2\x80\x94 如果它实际上是一个僵尸问题,你就不会预料到会崩溃。(我认为?)保留计数从 +2 跳到 0 可能也表明了除了简单的过度释放之外的其他原因。
\n\n那么我学到了什么?
\n\nrealloc
不使用其返回值进行调用是错误的,错误错误!遗憾的是静态分析器没有标记这一点。) 归档时间: |
|
查看次数: |
1208 次 |
最近记录: |