Wednesday, September 27, 2017

Swift 4 Weak References

Mike Ash:

In the old implementation, Swift objects have two reference counts: a strong count and a weak count. When the strong count reaches zero while the weak count is still non-zero, the object is destroyed but its memory is not deallocated. This leaves a sort of zombie object sitting in memory, which the remaining weak references point to.


Swift’s new implementation of weak references brings with it the concept of side tables.


To avoid reserving eight bytes for the side table, Swift makes a nifty optimization. Initially, the first word of an object is the class, and the next word stores the reference counts. When an object needs a side table, that second word is repurposed to be a side table pointer instead. Since the object still needs reference counts, the reference counts are stored in the side table. The two cases are distinguished by setting a bit in this field that indicates whether it holds reference counts or a pointer to the side table.

The side table allows Swift to maintain the basic form of the old weak reference system while fixing its flaws. Instead of pointing to the object, as it used to work, weak references now point directly at the side table.

Previously: Weak and Unowned References in Swift, How Swift Implements Unowned and Weak References, Swift’s Lazy Weak References.

Update (2019-02-22): David Smith:

I’ve seen some confusion about this recently, so figure it’s worth discussing: unowned in Swift is not like __unsafe_unretained in ObjC, and actually is pretty odd.

The difference is just that unowned deterministically guarantees a crash if misused, but that requires a lot:

In particular:

• A second reference count for unowned references is kept

• The object’s deinit runs when all strong references are gone, but it isn’t actually freed until unowned ones are too!

(Yes, unowned references still pay for atomic math; unowned(unsafe) avoids that)

This fixes the most common bizarre symptom of over-releases in ObjC: my object deallocated and a new unrelated object reused its memory. Usually this showed up as “unrecognized selector xyz sent to object of type <completely the wrong type how did this get here>”.

Comments RSS · Twitter

Leave a Comment