2011-06-07 18 views
229

在Mac和iOS平台中,内存泄漏通常是由未释放的指针引起的。传统上,检查分配,复制和保留以确保每个分配都有相应的释放消息一直是非常重要的。Objective-C中的自动引用计数不会阻止或最小化什么样的泄漏?

Xcode 4.2附带的工具链引入了最新版本的LLVM compiler的自动引用计数(ARC),通过让编译器将内存管理您的东西完全消除了这个问题。这非常酷,它确实减少了大量不必要的,平凡的开发时间,并且避免了大量的不小心内存泄漏,这些泄漏很容易通过适当的保留/释放平衡来修复。即使您为Mac和iOS应用启用ARC,也需要对自动恢复池进行不同的管理(因为您不应再分配自己的NSAutoreleasePool)。

但是什么其他内存泄漏是不是不是防止我还是要小心?

作为奖金,Mac OS X和iOS上的ARC以及Mac OS X上的垃圾收集有什么区别?

回答

257

您仍需要注意的主要内存相关问题是保留周期。这发生在一个对象具有强指向另一个的指针时,但目标对象具有强指向原始的指针。即使对这些对象的所有其他引用都被删除,它们仍然会保持对方,并且不会被释放。这也可以通过链中最后一个引用回早期对象的对象链间接发生。

正是因为这个原因,__unsafe_unretained__weak所有权限定符存在。前者不会保留它指向的任何对象,但会留下该对象消失的可能性,并指向不良内存,而后者不保留该对象,并在释放目标时自动将其自身设置为零。其中,__weak通常在支持它的平台上首选。

您可以使用这些限定符来处理委托等事情,您不希望对象保留其委托并可能导致循环。

另一个与内存有关的重要问题是处理核心基础对象和使用malloc()分配的内存类型,如char*。 ARC不管理这些类型,只有Objective-C对象,所以你仍然需要自己处理它们。核心基础类型可能特别棘手,因为它们有时需要桥接到匹配的Objective-C对象,反之亦然。这意味着当CF类型和Objective-C之间桥接时,控制需要从ARC中来回传输。一些与此桥接相关的关键字已被添加,并且Mike Ash对his lengthy ARC writeup中的各种桥接案例进行了很好的描述。

除此之外,还有其他几个不太常见但仍有潜在问题的情况,其中published specification会详细介绍。

许多新行为,基于保持对象的位置,只要有强指针指向它们,就非常类似于Mac上的垃圾收集。但是,技术基础非常不同。这种内存管理方式不是定期运行垃圾收集器进程来清理不再指向的对象,而是依赖于我们在Objective-C中需要遵守的严格的保留/释放规则。

ARC只需要我们多年来必须做的重复性内存管理任务,并将它们卸载到编译器中,因此我们再也不用担心它们了。这样,您就不会在垃圾收集平台上遇到暂停问题或锯齿形内存配置文件。我在垃圾收集的Mac应用程序中遇到过这两个问题,并且很想看看他们在ARC下的行为。

有关垃圾收集与ARC相关的更多信息,请参阅this very interesting response by Chris Lattner on the Objective-C mailing list,其中列出了ARC在Objective-C 2.0垃圾收集方面的许多优势。我遇到了他描述的几个GC问题。

+2

感谢您的详细回答。我遇到了同样的问题,我在_unsafe_unretained下定义了一个委托,并让我的应用程序崩溃,后来通过更改为强壮的方式修复了它,但现在它有内存泄漏。所以,我改变了它的弱点,像魅力一样运作。 – chathuram 2013-01-22 19:59:44

+0

@ichathura哇!你将我从ARC泥沼中拯救出来。我在使用CMPopTipView时遇到过相同的崩溃。 – Nianliang 2013-06-28 15:46:13

+0

@BradLarson:“你没有在垃圾收集平台上遇到的暂停问题或锯齿内存配置文件”。我期望从基于范围的回收中获得更差的停止和锯齿内存配置文件,以及引用计数的性能更差,所以我希望看到一个真正的比较。 – 2016-04-16 13:08:16

14

ARC不会帮你用非ObjC内存,例如你malloc()的东西,你还是需要free()吧。

如果编译器无法弄清楚选择器是什么(编译器会生成一个警告),ARC可能被performSelector:愚弄。

ARC还会根据ObjC命名约定生成代码,因此如果您混合使用ARC和MRC代码,那么如果MRC代码不执行编译器认为名称所承诺的内容,您可能会得到令人惊讶的结果。

0

ARC也不会管理CoreFoundation类型。你可以'桥接'它们(使用CFBridgingRelease()),但只有当你打算将它用作Objective-C/Cocoa对象时。请注意,CFBridgingRelease只是将CoreFoundation保留计数递减1,并将其移至Objective-C的ARC。