【问题标题】:What is automatic about Swift's Automatic Reference Counting?Swift 的自动引用计数是什么?
【发布时间】:2017-01-15 15:19:40
【问题描述】:

是否正在进行某种程序分析以在运行时减少/删除引用计数?或者它们只是“自动”的,因为程序员不需要手动增加和减少计数,但每当引用产生/消失时就会发生?

基本上,ARC 与普通引用计数有何不同?是否有任何已发表的论文讨论正在发生的事情,尤其是在使用程序分析的情况下?

【问题讨论】:

标签: swift memory-management automatic-ref-counting reference-counting


【解决方案1】:

是否正在进行某种程序分析以在运行时减少/删除引用计数?

不,正在进行程序分析以自动插入维护引用计数的调用。

或者它们只是“自动”的,因为程序员不需要手动增加和减少计数......

没错。在 ARC 之前,Objective-C 程序员必须小心地在想要维护对对象的引用时调用 -retain,并在完成引用时调用 -release。这些方法递增和递减对象的引用计数。使用 ARC,编译器会找出应该在哪里添加这些调用并插入它们(或等效代码)。所以从程序员的角度来看,引用计数是自动的。

【讨论】:

    【解决方案2】:

    自动引用计数 (ARC) 涉及编译时的静态分析,但执行任何运行时分析。

    将 ARC 概念化的简单方法是两遍过程。首先,它会检查您的代码并在引入对象引用和/或超出范围的地方插入内存管理代码(语义上等同于 ARC ObjC 之前的 retainrelease 调用)。所以这个:

    func doSomething() -> Object {
        let thing1 = Object(name: "foo")
        var thing2 = Object(name: "bar")
        thing2 = Object(name: "baz")
        return thing2
    }
    

    ...变成(以某种编译器内部的中间形式)如下:

    func doSomething() -> Object {
        let thing1 = Object(name: "foo")
        __retain(thing1) // increment reference count so thing1 sticks around
    
        var thing2 = Object(name: "bar")
        __retain(thing2) // increment reference count so thing2 sticks around
    
        let oldThing2 = thing2 // thing2 gets replaced on the next line
        thing2 = Object(name: "baz")
        __release(oldThing2) // get rid of the thing that got overwritten
        __retain(thing2) // hold onto the new thing that replaced it
    
        __release(thing1) // end of scope, so nothing else will use thing1
        return __autorelease(thing2) // relinquish ownership of thing2,
            // but only upon handing ownership over to our caller
    }
    

    引入对象引用的时间以及它们超出范围或移交给调用者的时间(通过return 语句)是逐行满足程序语义的最低要求,但到此为止分析级别导致冗余内存管理。 (例如,请注意 thing1 在创建后从未使用过。)因此 ARC 所做的下一件事是进行流分析以消除冗余并执行其他优化,使我们的示例伪代码更像这样:

    func doSomething() -> Object {
        _ = Object(name: "foo") // formerly thing1
        // Object.init(name:) is called in case it has side effects, 
        // but the result is immediately discarded because it's not used
    
        _ = Object(name: "bar") // formerly thing2
        // again we call the initializer but discard the result,
        // because the original thing2 is immediately overwritten
    
        let thing2 = Object(name: "baz")
        // no retain, because nothing happens between here and return
        // that could affect the memory lifetime of thing2
    
        return __magic_autorelease(thing2) 
        // and there's other voodoo we can do to ensure handoff to the caller
        // without getting into retain count tracking or autorelease pools
    }
    

    这显然是一个非常随意的概述 - 引擎盖下还有很多事情要做,所以真正的实现并不完全适合这个简单的两步过程,但在概念上它非常相似。有关更详细的讨论,请查看:

    前两个是关于 Objective-C 中的 ARC,但 Swift 中的 ARC 密切相关,所以如果你想知道 ARC 的真正工作原理,最好看看它的 ObjC 起源。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-20
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-10
      • 2014-12-27
      • 1970-01-01
      相关资源
      最近更新 更多