有人可以简要向我解释ARC的工作原理吗?我知道它与垃圾收集有所不同,但是我只是想知道它是如何工作的。
此外,如果ARC在不影响性能的情况下执行GC的功能,那么Java为什么要使用GC?为什么还不使用ARC?
有人可以简要向我解释ARC的工作原理吗?我知道它与垃圾收集有所不同,但是我只是想知道它是如何工作的。
此外,如果ARC在不影响性能的情况下执行GC的功能,那么Java为什么要使用GC?为什么还不使用ARC?
Answers:
每个使用Objective-C的新开发人员都必须学习何时保留,释放和自动释放对象的严格规则。这些规则甚至指定了命名约定,这些约定暗示从方法返回的对象的保留计数。一旦您牢记这些规则并一致地应用它们,Objective-C中的内存管理就成为了第二天性,但是即使是最有经验的Cocoa开发人员也会时不时地滑倒。
借助Clang静态分析器,LLVM开发人员意识到这些规则足够可靠,因此他们可以构建一个工具来指出代码采用的路径中的内存泄漏和过高释放。
自动参考计数(ARC)是下一个逻辑步骤。如果编译器可以识别应保留和释放对象的位置,为什么不让它为您插入该代码呢?刚性的,重复性的任务是编译器及其兄弟们擅长的。人们会忘记事情并犯错误,但是计算机的一致性更高。
但是,这并不能完全让您不必担心这些平台上的内存管理。我在这里的回答中描述了要注意的(保留周期)主要问题,这可能需要您一些思考以标记弱指针。但是,与您在ARC中获得的相比,这是次要的。
与手动内存管理和垃圾回收相比,ARC通过消除编写保留/释放代码的需要,为您提供了两全其美的优势,但又没有垃圾回收环境中出现的暂停和锯齿式内存配置文件。现在唯一的优势垃圾收集有超过这个是它对付保留周期,事实上,原子属性分配是廉价的(所讨论的能力在这里)。我知道我将所有现有的Mac GC代码替换为ARC实现。
至于是否可以将其扩展到其他语言,似乎围绕着Objective-C中的引用计数系统。将其应用于Java或其他语言可能很困难,但是我对低级编译器的详细信息了解不足,无法在那里做出明确的声明。鉴于苹果公司是在LLVM中推动这一努力的人,除非有另一方为此投入大量资源,否则Objective-C将排在第一位。
WWDC上的开发人员震惊的揭幕,所以人们并不知道可以做这样的事情。随着时间的流逝,它可能会出现在其他平台上,但目前它是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与ARC相比,可预测的CPU /内存需求较低,并且性能(通常)较低,但可以处理任何使用模式。ARC在许多常见的使用模式下会更好地工作,但是在某些(有效!)使用模式下,它会崩溃并死掉。
foo = nil
。
魔法
但更具体地说,ARC的工作原理与代码完全相同(有一些细微差别)。ARC是一种编译时技术,与GC不同,后者是运行时,会对性能产生负面影响。ARC将为您跟踪对对象的引用,并根据正常规则综合保留/释放/自动释放方法。因此,ARC也可以在不再需要它们时立即释放它们,而不是纯粹出于约定而将它们扔到自动释放池中。
其他一些改进包括将弱引用归零,将块自动复制到堆,全面加速(自动释放池提高6倍!)。
有关所有这些工作原理的更详细讨论,请参见ARC上的LLVM文档。
它与垃圾收集有很大的不同。您是否已看到警告,告知您可能正在不同的行上泄漏对象?这些语句甚至告诉您分配对象的位置。这已经向前迈进了一步,现在可以将retain
/ release
语句插入适当的位置,比大多数程序员要好,几乎100%的时间。有时候,您需要一些奇怪的保留对象实例来帮助解决问题。
Apple开发人员文档对此进行了很好的解释。阅读“ ARC的工作原理”
为了确保实例在仍然需要时不会消失,ARC跟踪当前引用每个类实例的属性,常量和变量的数量。只要仍存在至少一个对该实例的活动引用,ARC便不会取消分配该实例。
为了确保实例在仍然需要时不会消失,ARC跟踪当前引用每个类实例的属性,常量和变量的数量。只要仍存在至少一个对该实例的活动引用,ARC便不会取消分配该实例。
认识Diff。在垃圾回收和ARC之间:阅读本
ARC是一种编译器功能,可提供对象的自动内存管理。
ARC 无需评估何时使用retain, release
和autorelease
,而是可以评估对象的生存期要求并在编译时自动为您插入适当的内存管理调用。编译器还会为您生成适当的dealloc方法。
编译器retain/release
在编译时插入必要的调用,但是这些调用在运行时执行,就像其他任何代码一样。
下图将使您更好地了解ARC的工作方式。
那些是iOS开发的新手,并且没有在Objective C上的工作经验。请参阅Apple的《高级内存管理编程指南》文档,以更好地了解内存管理。