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

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

另外,如果ARC在不妨碍性能的情况下执行GC的操作,那么Java为什么使用GC? 为什么不使用ARC呢?

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

通过Clang静态分析器,LLVM开发人员意识到这些规则足够可靠,可以构建一个工具来指出代码所用路径中的内存泄漏和过度释放。

自动引用计数 (ARC)是下一个逻辑步骤。 如果编译器可以识别你应该保留和释放的对象,为什么不把它插入你的代码? 刚性的,重复的任务是编译器和他们的弟兄所擅长的。 人类忘记了事情,犯了错误,但电脑更加一致。

但是,这并不能让你完全免于担心这些平台上的内存管理。 我在这里的回答中描述了要留意(保留周期)的主要问题,这可能需要你稍微考虑一下,以标记弱指针。 然而,这与你在ARC中获得的东西相比是微不足道的。

与手动内存管理和垃圾收集相比,ARC通过削减编写保留/释放代码的需求,为您提供两全其美的解决方案,但却无法在垃圾收集环境中看到停止和锯齿内存配置文件。 关于垃圾收集在这方面唯一的优点是它处理保留周期的能力和原子属性分配是便宜的(如这里所讨论的)。 我知道我用ARC实现替换了所有现有的Mac GC代码。

至于这是否可以扩展到其他语言,似乎围绕Objective-C中的引用计数系统。 这可能很难将其应用于Java或其他语言,但是我对低级编译器的详细信息不够了解,无法在此处作出明确的说明。 鉴于苹果是LLVM推动这一努力的一员,Objective-C将首先出现,除非另一方为此付出巨大的资源。

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

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

另一方面,某些类型的数据结构对于ARC(或MRC)是不可能的,而GC可以处理它们。

作为一个例子,如果你有一个名为node的类,并且node有一个NSArray的子​​对象,并且对它的父对象“可以正常工作”。 使用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,并希望通过父指针爬回来,并找到答:如果你只有坚持B1,弱的参考,A可以(通常会)蒸发,并采取B2和B3用它。

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

所以ARC针对GC目标的相同问题。 然而,ARC使用更多的使用模式,然后使用GC,所以如果你使用了一种GC语言(比如Java),并且把ARC这样的东西嫁接到它上面,一些程序就不能再工作了(或者至少会产生大量的被遗弃的内存,并可能导致严重的交换问题或内存不足或交换空间)。

你也可以说,ARC把性能放在更重要的位置(或者可能是可预测的),而GC则把更大的优先考虑作为一个通用的解决方案。 因此GC对CPU /内存的要求较低,性能(通常)低于ARC,但可以处理任何使用模式。 ARC对很多很多常见的使用模式都会有很好的效果,但是对于一些(有效的)使用模式,它会崩溃并死亡。

魔法

但更具体地说,ARC通过完成您的代码(具有一些细微差别)来完成工作。 ARC是一种编译时技术,与运行时不同的GC不同,会对性能造成负面影响。 ARC将跟踪对象的引用,并根据正常规则合成保留/释放/自动释放方法。 由于这个ARC也可以在不再需要的时候释放它,而不是仅仅为了传统的目的而将它们放入自动释放池中。

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

关于如何运作的详细讨论可以在ARC的LLVM文档中找到。

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

Apple开发者文档很好地解释了这一点。 阅读“ARC如何工作”

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

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

要知道差异。 垃圾收集和ARC之间:阅读此