Reputation: 8423
Is there some sort of program-analysis going on to reduce/remove the reference-counts at runtime? Or are they just "automatic" in the sense that the programmer doesn't need to manually increment and decrement the count, but it happens whenever references are made/disappear?
Basically, what makes ARC different from normal reference counting? Are there any published papers discussing what's going on, particularly if it is using program analysis?
Upvotes: 1
Views: 661
Reputation: 126127
Automatic Reference Counting (ARC) involves static analysis at compile time, but does not perform any runtime analysis.
The easy way to conceptualize ARC is as a two-pass process. First, it examines your code and inserts memory management code (semantically equivalent to the retain
and release
calls of pre-ARC ObjC) in the places where object references are introduced and/or go out of scope. So this:
func doSomething() -> Object {
let thing1 = Object(name: "foo")
var thing2 = Object(name: "bar")
thing2 = Object(name: "baz")
return thing2
}
...becomes (in some compiler-internal intermediate form) something like this:
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
}
The times when object references are introduced and the times they go out of scope or are handed off to a caller (through a return
statement) are the minimum requirement to fulfill program semantics from line to line, but stopping at this level of analysis leads to redundant memory management. (Note for example that thing1
is never used after its creation.) So the next thing ARC does is a flow analysis to eliminate redundancies and perform other optimizations, making our example pseudocode something more like this:
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
}
This is obviously a very hand-wavy overview — there's a lot more going on under the hood, so the real implementation doesn't quite fit this simple two-step process, but conceptually it's very similar. For some more detailed discussion, take a look at:
The first two of those are about ARC in Objective-C, but ARC in Swift is very closely related, so if you want to know how ARC really works it's best to look at its ObjC origins.
Upvotes: 2
Reputation: 124997
Is there some sort of program-analysis going on to reduce/remove the reference-counts at runtime?
No, there's program analysis going on to automatically insert the calls that maintain the reference counts.
Or are they just "automatic" in the sense that the programmer doesn't need to manually increment and decrement the count...
Exactly. Before ARC, Objective-C programmers had to be careful to call -retain
on an object when they wanted to maintain a reference to it, and -release
when they were done with the reference. Those methods incremented and decremented the object's reference count. With ARC, the compiler figures out where those calls should be added and inserts them (or equivalent code). So the reference counting is automatic from the programmer's point of view.
Upvotes: 1