谁能简单地给我解释一下ARC是如何工作的?我知道它不同于垃圾收集,但我只是想知道它究竟是如何工作的。
而且,如果ARC在不影响性能的情况下完成了GC的工作,那么Java为什么要使用GC呢?为什么不使用ARC呢?
谁能简单地给我解释一下ARC是如何工作的?我知道它不同于垃圾收集,但我只是想知道它究竟是如何工作的。
而且,如果ARC在不影响性能的情况下完成了GC的工作,那么Java为什么要使用GC呢?为什么不使用ARC呢?
它与垃圾收集有很大的不同。您是否看到警告,告诉您可能在不同的行上泄漏对象?这些语句甚至告诉你在第几行分配了对象。这已经更进一步,现在可以在适当的位置插入保留/释放语句,比大多数程序员更好,几乎100%的时间。偶尔会有一些奇怪的保留对象的实例,您需要帮助它。
魔法
But more specifically ARC works by doing exactly what you would do with your code (with certain minor differences). ARC is a compile time technology, unlike GC which is runtime and will impact your performance negatively. ARC will track the references to objects for you and synthesize the retain/release/autorelease methods according to the normal rules. Because of this ARC can also release things as soon as they are no longer needed, rather than throwing them into an autorelease pool purely for convention sake.
其他一些改进包括弱引用归零、自动将块复制到堆、全面加速(自动释放池的速度为6倍!)
关于这一切如何工作的更详细的讨论可以在ARC上的LLVM文档中找到。
每个接触Objective-C的新开发人员都必须学习何时保留、释放和自动释放对象的严格规则。这些规则甚至指定了暗示从方法返回的对象的保留计数的命名约定。一旦你把这些规则牢记于心并始终应用它们,Objective-C中的内存管理就会成为你的第二天性,但即使是最有经验的Cocoa开发人员也会时不时地犯错。
使用Clang Static Analyzer, LLVM开发人员意识到这些规则足够可靠,他们可以构建一个工具来指出代码所采用的路径中的内存泄漏和过度释放。
自动引用计数(ARC)是下一个逻辑步骤。如果编译器能够识别应该在哪里保留和释放对象,为什么不让它为您插入代码呢?严格的、重复的任务是编译器及其同类所擅长的。人类会忘记事情,会犯错误,但计算机的一致性要高得多。
然而,这并不能让您完全摆脱对这些平台上内存管理的担忧。我在这里的回答中描述了要注意的主要问题(保留周期),这可能需要您花一点心思来标记弱指针。然而,与您在ARC中获得的相比,这是次要的。
When compared to manual memory management and garbage collection, ARC gives you the best of both worlds by cutting out the need to write retain / release code, yet not having the halting and sawtooth memory profiles seen in a garbage collected environment. About the only advantages garbage collection has over this are its ability to deal with retain cycles and the fact that atomic property assignments are inexpensive (as discussed here). I know I'm replacing all of my existing Mac GC code with ARC implementations.
至于这是否可以扩展到其他语言,它似乎与Objective-C中的引用计数系统有关。将其应用于Java或其他语言可能很困难,但我对底层编译器的细节了解不够多,无法对此做出明确的说明。考虑到Apple是LLVM中推动这项工作的一方,Objective-C将首先出现,除非另一方将自己的大量资源投入其中。
这一消息的公布震惊了全球开发者大会上的开发者,所以人们没有意识到这样的事情是可以做到的。随着时间的推移,它可能会出现在其他平台上,但目前它只适用于LLVM和Objective-C。
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会工作得更好,但对于少数(有效的!)使用模式,它会崩溃并死亡。
苹果开发者文档解释得很好。阅读“ARC如何工作”
To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists. To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
要了解垃圾收集和ARC之间的区别:阅读这篇文章
ARC是一个编译器特性,提供对象的自动内存管理。
您不必记住何时使用保留、释放和自动释放,ARC会评估对象的生命周期需求,并在编译时自动为您插入适当的内存管理调用。编译器还为您生成适当的dealloc方法。
编译器在编译时插入必要的retain/release调用,但这些调用在运行时执行,就像任何其他代码一样。
下面的图表将使您更好地理解ARC的工作原理。
那些刚接触iOS开发,没有Objective C工作经验的人。 为了更好地理解内存管理,请参考Apple的高级内存管理编程指南文档。