首页 文章

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

提问于
浏览
201

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

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

5 回答

  • 22

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

  • 241

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

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

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

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

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

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

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

  • 0

    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将更好地工作,但是对于一些(有效的!)使用模式,它将会崩溃并死亡 .

  • 4

    Magic

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

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

    关于如何工作的更详细的讨论可以在ARC的LLVM Docs中找到 .

  • 3

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

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

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

相关问题