使用ARC的优缺点是什么?

42

使用新的自动引用计数 (ARC) 内存管理风格在 iOS 项目中有什么优缺点?

在使用 iOS 5.0 SDK 进行开发时,您是否可以选择不使用 ARC?

对于一个新项目,您推荐使用 ARC 还是手动引用计数 (MRC)?

使用 ARC 的应用程序能否在早于 iOS 5.0 的旧操作系统版本上运行?


2
您在这里有几个问题,其中两个在以下问题中得到了解答:新的自动引用计数机制是如何工作的?Xcode 4.2与ARC:即使在低于5.0固件的iOS设备上,我的代码也能运行吗? - Brad Larson
4个回答

58
在iOS项目中使用新的自动引用计数(ARC)内存管理风格的优缺点是什么?
ARC程序的执行几乎与良好编写的MRC相同。也就是说,行为上的差异通常是无法检测到的,因为操作顺序和性能非常接近。
如果您已经知道如何使用手动引用计数(MRC)实现OS X或iOS应用程序,则ARC实际上并没有添加功能,它只允许您从源代码中删除引用计数操作。
如果您不想学习MRC,那么您可能想首先尝试ARC。很多人都会遇到MRC的一些常见问题(例如:我向一些objc开发人员介绍了静态分析器),或者试图忽略这些问题。如果您想避免这些问题,ARC将允许您推迟理解;无论是MRC、ARC还是GC,您都不能编写非平凡的objc程序而不了解引用计数和对象生命周期及关系。ARC和GC只是从您的源代码中删除了实现,并且在大多数情况下做正确的事情。使用ARC和GC仍然需要一些指导。
我没有测量过这一点,但值得一提的是,编译ARC源代码可能需要更多的时间和资源。
如果您正在开发的程序对引用计数的使用相当松散(例如:典型的自动释放量),那么切换到ARC可能会真正提高您程序的执行时间和峰值内存使用率。
在iOS 5.0 SDK开发时,您可以选择不使用ARC吗?
是的,使用CLANG_ENABLE_OBJC_ARC。ARC是二进制兼容的,实际上编译器会根据当前翻译可见的声明自动引入适当的引用计数操作,使您的代码更加简洁明了(有关为什么翻译可见性很重要,请参见我的答案)。因此,您还可以在项目中启用和禁用它以及为其他源启用它。
然而,混合模式(一些MRC和一些ARC源)相当复杂,尤其是对于可能被编译器复制的实现(例如,内联函数的主体可能不正确)。这样的混合模式问题将非常难以隔离。ObjC++程序和源将在这方面特别困难。此外,行为可能会根据您的优化设置而有所不同(作为一个例子);一个在调试版本中完美运行的程序可能会在发布版本中引入泄漏或僵尸对象。
“你推荐新项目使用ARC还是手动引用计数(MRC)呢?
个人而言,我会继续使用MRC一段时间。即使ARC已经在实际应用中进行了测试,仍然可能存在一些问题,在复杂场景下会显露出来,你肯定不想成为第一个发现并调试这些问题的人。OS X的垃圾回收就是一个例子,你可能想等待一段时间。例如,这个转换可能会改变对象何时被销毁--您的对象可能会更早地被销毁并且永远不会被放置在自动释放池中。它还可以更改ivars释放的顺序,这可能会产生一些副作用。
我还有一个庞大的代码库,此时不想花费一周时间测试此功能。最后,对于我来说向后兼容仍然很重要。

使用ARC的应用程序能在iOS 5.0以下的旧版本上运行吗?

如果使用MRC进行开发,则可以实现向后兼容。如果使用ARC进行开发,则不一定兼容。实际上,可能需要进行一些额外的工作才能编译。运行时的要求在某些较早的版本中可用。另请参见此问题。如果需要向后兼容性,则对于某些操作系统版本,ARC将不是一个选项。
最后,如果限制选择为GC或ARC,则建议选择ARC。

5
非常好的评论。我们讨论了将我们的大型企业项目从MRC迁移到ARC,但我们认为对于大型项目或具有复杂对象模型的项目使用MRC更好,因为我们可以控制它。在大多数情况下,我们甚至不需要手动调用retain/release。我们为所有东西都有保留属性,并在分配时自动释放。但是偶尔我们会遇到需要直接控制内存的情况。 - Sulthan
我花了不是一周而是两天时间来迁移我的基于OpenGL ES的2D库,我可以告诉你...如果你一直直接访问ivars(为了避免开销,并且因为你知道自己在做什么),你会有很多委托对象散布在各处,而你忘记添加__unsafe_unretained等...你可能会遇到很多保留周期,在实现-dealloc时只是添加一个NSLog以查看对象是否被释放,在我的情况下会带来很多头痛。再加上Xcode兼容性问题、助手中的错误、失败的迁移... - Nicolas Miari
目前,我将采用ARC,但仅适用于小型的基于UIKit的项目,其中我可以负担得起一直使用self.this self.that,并且所有内容都符合Apple预见的用例。 - Nicolas Miari

1

你可以使用CLANG_ENABLE_OBJC_ARC = NO来关闭/打开它。 优点是你需要编写的代码更少,内存管理更容易。缺点是你必须放弃你所学习的关于内存管理的一切 :) 我更喜欢关闭它。


如果您使用ARC,也可能会有一些小的性能损失。 - Thomas K
实际上,ARC在运行时通常更快,主要是因为优化器尽早释放对象,并且较少依赖自动释放池。 - pchap10k
2
这比较复杂。ARC 在不同情况下既更快又更慢。典型的结果是:更多的保留和释放(更慢),更少的自动释放(更快,内存更少)。唯一确定它对于你特定代码是更快还是更慢的方法是进行测量。 - Catfish_Man

0

我正在使用Lion和Xcode 4.3。

我也遇到了同样的问题。

为了解决这个问题,我将"Build Settings->Objective-C Automatic Reference Co"设置成了"No"。

为了查看是否已经设置为"Yes",我还需要在"Build Settings"工具栏下方的工具栏中启用"All"和"Levels"选项。

一旦这些选项被启用,我就可以看到我的项目已经将该选项设置为"Yes"。由于默认设置为"No",因此在启用"Levels"选项之前,我花了一段时间才弄清楚。


0
你可以通过“编辑->重构->转换为Objective C Arc”来开启ARC,这将完全重构你的代码(摆脱所有的内存管理调用等)。没有相反的操作,所以如果你有所顾虑,请确保你已经掌握了源代码控制。这篇文章向你展示了如何针对特定文件禁用它。我认为除了看到所有这些良好的内存管理努力付之东流并且我们不得不停止每次看到init、new、copy而没有相应的release/autorelease时跳到天花板上(这需要一些时间适应),没有太多争论的余地。也许可以说,在某些情况下,手动内存管理会导致真正显著的性能/内存占用改进,如果是这样,我也很感兴趣。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接