新的自动引用计数机制如何工作?

时间:2011-06-17 11:40:40

标签: objective-c cocoa-touch garbage-collection automatic-ref-counting

有人可以简单地向我解释ARC是如何工作的吗?我知道它与垃圾收集不同,但我只是想知道它是如何工作的。

另外,如果ARC在没有阻碍性能的情况下完成了GC的工作,那么为什么Java会使用GC呢?为什么不使用ARC呢?

6 个答案:

答案 0 :(得分:242)

每个来到Objective-C的新开发人员都必须学习何时保留,释放和自动释放对象的严格规则。这些规则甚至指定了命名约定,这些约定意味着从方法返回的对象的保留计数。一旦你把这些规则牢记在心,并且一致地应用它们,Objective-C中的内存管理就变成了第二天性,但即使是最有经验的Cocoa开发人员也会不时地滑倒。

使用Clang Static Analyzer,LLVM开发人员意识到这些规则足够可靠,他们可以构建一个工具来指出代码所在路径中的内存泄漏和过度发布。

Automatic reference counting(ARC)是下一个合乎逻辑的步骤。如果编译器可以识别您应该保留和释放对象的位置,为什么不让它为您插入该代码?严格的,重复性的任务是编制者及其兄弟们所擅长的。人类会忘记事情并犯错误,但计算机更加一致。

然而,这并不能完全让您免于担心这些平台上的内存管理。我在回答here中描述了要注意(保留周期)的主要问题,这可能需要您仔细考虑标记弱指针。但是,与您在ARC中获得的相比,这是次要的。

与手动内存管理和垃圾收集相比,ARC通过减少编写保留/释放代码的需要为您提供了两全其美的优势,但却没有在垃圾回收环境中看到暂停和锯齿内存配置文件。关于垃圾收集对此的唯一优势是它处理保留周期的能力以及原子属性分配便宜的事实(如here所述)。我知道我正在用ARC实现替换所有现有的Mac GC代码。

至于是否可以将其扩展到其他语言,它似乎围绕着Objective-C中的引用计数系统。将它应用于Java或其他语言可能很困难,但我对低级编译器细节知之甚少,无法在那里做出明确的声明。鉴于Apple是在LLVM中推动这项工作的人,Objective-C将首先出现,除非另一方为此投入大量资源。

WWDC上这些震惊的开发者揭幕,所以人们不知道可以做到这样的事情。随着时间的推移,它可能出现在其他平台上,但目前它仅限于LLVM和Objective-C。

答案 1 :(得分:22)

ARC只是玩旧保留/释放(MRC),编译器确定何时调用保留/释放。与GC系统相比,它具有更高的性能,更低的峰值内存使用率和更可预测的性能。

另一方面,ARC(或MRC)无法使用某些类型的数据结构,而GC可以处理它们。

例如,如果您有一个名为node的类,并且node有一个NSArray子节点,并且对其父节点的单个引用“只适用于GC”。使用ARC(以及手动引用计数),您会遇到问题。任何给定节点都将从其子节点以及其父节点引用。

像:

A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A

当你使用A时(例如通过局部变量),一切都很好。

当你完成它(和B1 / B2 / B3)时,GC系统最终将决定从堆栈和CPU寄存器开始查看它能找到的所有内容。它永远不会找到A,B1,B2,B3,因此它将最终确定它们并将内存回收到其他对象中。

当您使用ARC或MRC,并以A结束时它的引用数为3(B1,B2和B3都引用它),而B1 / B2 / B3的引用计数均为1(A的NSArray保持不变)每个参考一个)。因此,即使没有任何东西可以使用它们,所有这些对象仍然存在。

常见的解决方案是确定其中一个引用需要较弱(不参与引用计数)。这适用于某些使用模式,例如,如果仅通过A引用B1 / B2 / B3。但是在其他模式中它会失败。例如,如果你有时会保持B1,并期望通过父指针向上爬回来并找到A.如果你只持有B1,则弱参考,A可以(并且通常会)蒸发,并取B2和B3用它。

有时候这不是一个问题,但使用复杂的数据结构的一些非常有用和自然的方法很难用于ARC / MRC。

因此ARC针对GC目标提出同样的问题。然而,ARC使用的是一组比GC更有限的使用模式,所以如果你使用GC语言(比如Java)并将ARC这样的东西嫁接到它上面,一些程序将不再起作用(或者至少会产生大量废弃的内存) ,并可能导致严重的交换问题或内存不足或交换空间。)

您还可以说ARC更重视性能(或可预测性),而GC则更加重视通用解决方案。因此,GC具有较少的可预测CPU /内存需求,并且性能(通常)低于ARC,但可以处理任何使用模式。对于许多常见的使用模式,ARC会更好地工作,但对于一些(有效的!)使用模式,它将会崩溃并死亡。

答案 2 :(得分:4)

<强>万

但更具体地说,ARC的工作方式与您对代码的处理方式完全相同(具有一些细微差别)。 ARC是一种编译时技术,与运行时GC不同,它会对您的性能产​​生负面影响。 ARC将为您跟踪对象的引用,并根据常规规则合成retain / release / autorelease方法。因此,ARC可以在不再需要时立即释放,而不是仅仅为了传统而将它们放入自动释放池中。

其他一些改进包括将弱引用归零,将块自动复制到堆中,全面加速(自动释放池为6倍!)。

有关如何运作的更详细讨论,请参阅ARC上的LLVM Docs

答案 3 :(得分:3)

它与垃圾收集有很大不同。您是否看到过警告,告诉您可能在不同线路上泄漏物体?这些语句甚至会告诉您分配对象的行。这已经更进了一步,现在可以在适当的位置插入retain / release语句,比大多数程序员更好,几乎100%的时间。偶尔会有一些奇怪的保留对象实例需要帮助它。

答案 4 :(得分:0)

Apple开发人员文档很好地解释了这一点。阅读"How ARC Works"

  

为了确保实例在仍然需要时不会消失,ARC会跟踪当前引用每个类实例的属性,常量和变量的数量。只要至少有一个对该实例的活动引用仍然存在,ARC就不会解除分配实例。

     

为了确保实例在仍然需要时不会消失,ARC会跟踪当前引用每个类实例的属性,常量和变量的数量。只要至少有一个对该实例的活动引用仍然存在,ARC就不会解除分配实例。

了解差异。垃圾收集和ARC之间:阅读this

答案 5 :(得分:0)

ARC是一种编译器功能,可提供对象的自动内存管理。

ARC无需评估何时使用retain, releaseautorelease,而是可以评估对象的生存期要求,并在编译时自动为您插入适当的内存管理调用。编译器还会为您生成适当的dealloc方法。

编译器在编译时插入必要的retain/release调用,但是这些调用与其他任何代码一样在运行时执行。

下图将使您更好地了解ARC的工作原理。

enter image description here

iOS开发的新手,并且没有在Objective C上的工作经验。 请参阅Apple文档Advanced Memory Management Programming Guide,以更好地了解内存管理。