在 iOS 4.0 上释放 Autoreleasepool 崩溃(以及在 4.1 上......)

Posted

技术标签:

【中文标题】在 iOS 4.0 上释放 Autoreleasepool 崩溃(以及在 4.1 上......)【英文标题】:Releasing Autoreleasepool crashes on iOS 4.0 (and on 4.1 as well..) 【发布时间】:2010-12-17 10:32:02 【问题描述】:

我想知道是什么原因造成的。 我的代码中有几个使用 performSelectorInBackground 调用的方法。 在这些方法中的每一个中,我都有一个 Autoreleasepool,它在开始时被分配/初始化,并在方法结束时被释放。

这在 ios 3.1.3 / 3.2 / 4.2 / 4.2.1 上完美运行,但它在 iOS 4.0 上致命地崩溃,并在调用 [myPool release] 后发生 EXC_BAD_ACCESS 异常。

在我注意到这种奇怪的行为后,我正在考虑重写我的部分代码并让我的应用程序“不那么并行”,以防客户端操作系统是 4.0。

在我这样做之后,应用程序崩溃的下一个点是来自 Apples Reachability“框架”的 ReachabilityCallback-Method。

好吧,现在我不太确定该怎么做。

我在线程方法中所做的事情是非常简单的 xml 解析(没有可可调用或会影响 UI 的东西)。在每个方法完成后,它会发布一个通知,协调线程会监听,一旦所有并行化的方法完成,协调线程就会调用视图控制器等......

我完全不知道是什么导致了这种奇怪的行为。尤其是因为 Apples 代码也失败了。

非常感谢任何帮助!

谢谢, 山姆

【问题讨论】:

您使用的是哪个编译器? (GCC、LLVM 和 GCC 还是 LLVM?) 你的 gdb 描述是什么? 我正在使用 GCC 进行编译...@raaz:我如何获得 gdb 描述? 【参考方案1】:

检测僵尸的最佳方法是:

    Groups and Files 部分中,展开 Executables 部分并右键单击您的应用名称并选择 Get Info 选择顶部的Arguments 标签,然后在Variables 中添加一个新条目以在环境部分进行设置。将新变量命名为 NSZombieEnabled 并将其值设置为 YES

在此之后,您将在控制台中获得有关您调用了哪些已发布对象的信息。

【讨论】:

【参考方案2】:

好像我已经解决了这个问题。 问题是,(正如你们中的许多人所建议的那样)我在调用 [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error]; 的方法中过度发布了一个 NSURL 对象

我假设stringWithContentsOfURL 自动释放我作为参数传递的 NSURL 对象。

删除urlRequest 上的版本后,问题消失了。我仍然认为不同的 iOS 版本在这件事上的行为不同是很奇怪的。

整个方法如下所示:

-(NSString*)downloadContent:(NSURL*)urlRequest

NSString *data = nil;

NSError *error = nil;

data = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&error];    

//[urlRequest release]; //Crashes on iOS 4.0 / 4.1 later when autoreleasepool is being released.

return data;    

【讨论】:

【参考方案3】:

听起来好像在自动释放池范围内创建的自动释放对象正在被释放到不应该在的地方。不确定为什么行为与 SDK 版本不同;一定存在导致问题的某个地方的实现差异。您是否使用“构建和分析”构建了代码?这是否表明某些内容可能被过度发布?

【讨论】:

我检查并仔细检查。执行上绝对没有区别。幸运的是,它现在可以工作了.. 分析器说这是一个潜在的泄漏,但是哦,好吧.. 什么不是 :)【参考方案4】:

我还注意到performSelectorInBackground 的一些奇怪行为。我可能完全错了,但就我而言,我使用过:

[NSThread detachNewThreadSelector:@selector(blah) toTarget:self withObject:nil];

效果更好。如果您在使用该方法时需要访问主线程(例如更新 UI),您可以:

[self performSelectorOnMainThread:@selector(blah2) withObject:nil waitUntilDone:false];

【讨论】:

以上是关于在 iOS 4.0 上释放 Autoreleasepool 崩溃(以及在 4.1 上......)的主要内容,如果未能解决你的问题,请参考以下文章

75. Autorelease机制及释放时机

在 iOS 4.0 上释放 Autoreleasepool 崩溃(以及在 4.1 上......)

iOS开发-34自己主动释放池@autoreleasepool的使用注意事项以及ARC机制——面试必考内容

iOS 基础知识整理(不间断更新)

iOS---NSAutoreleasePool自动释放原理及详解

iOS之内存管理(ARC)