Friday Q & A 2017-09-22: Swift 4 Weak References
For those of you who have forgotten the old implementation and do not Feel to read through the last article, let's briefly recognize how it works.
In the old implementation, Swift objects have two reference values: a strong count and a weak count. When the strong count reaches zero, while the weak count is still zero, the object is destroyed, but its memory is not deallocated. This leaves a kind of zombie object that is in memory, as the remaining weak references point to.
When a weak reference is loaded, the runtime checks to see if the object is a zombie. If it is, it resets the weak reference and reduces weak reference count. When the weak count reaches zero, the object's memory is allocated. This means that zombie objects will eventually be deleted when all weak references to them are available.
I loved the simplicity of this implementation, but it had some errors. One mistake was that the zombie objects could keep in memory for a long time. For classes with large occurrences (because they contain many properties, or use something like
ManagedBuffer to assign additional memory input), this can be a serious waste.
Another problem that I discovered after writing the old article was that the implementation was not thread-safe for simultaneous reading. Oops! This was patched, but the discussion around it showed that the implementers wanted a better implementation of weak references anyway, which would be more resistant to such things.
There are many data materials that constitute "an object" in Swift.
First and foremost, all the stored properties are declared in the source code. These are directly available by the programmer.
Secondly, the object's class. This is used for dynamic shipment and
type (of :) built-in function. This is mostly hidden, although dynamic shipment and
type (of :) implies its existence.
Third, there are the different reference numbers. These are completely hidden if you do not do scary things like reading the raw memory of the object or convincing the compiler that you can call
Fourth, you have additional information stored by Objective-C runtime, as a list of objective-C weak references (Goal-C implementation of weak references traces each weak reference individually) and associated objects.
Where do you store all these things?
In Target C, the class and stored properties (ie instance variables) are stored inline in the object's memory. The class takes up the first pointer size, and the occurrence variables are followed. Additional information is stored in external tables. When you manipulate an associated item, the driving time looks up in a large hashboard typed by the object's address. This is something slow and requires locking so that multithreaded access does not fail. The reference count is sometimes stored in the object's memory and sometimes stored in an external table, depending on which OS version you are running and which CPU architecture.
In Swift's old implementation, the class, reference number and stored properties were all stored inline. Help data was still stored in a separate table.
Proposed how these languages actually do, let's ask the question: how should
they do it?
Each place has a deviation. Data stored in the object's memory is quickly accessible, but always takes place. Data stored in an external table is slower to access, but takes up zero space for objects that do not need it.
This is at least part of why Objective-C traditionally did not save the reference count in the object itself. Lens-C reference count was created when computers were much less skilled than they were now and the memory was extremely limited. Most objects in a typical Objective-C program have a single owner, and thus a reference number of 1
1will always be wasteful. Using an external table, the common value of
1can be represented in the absence of an entry, which reduces memory usage.
Each item has a class and is continuously available. Each dynamic method call needs it. This should go directly to the object's memory. There are no savings by storing it externally.
Saved properties are expected to be fast. If an item has them, determine at the compilation time. Objects without stored properties can assign zero space to themselves when they are stored in the object's memory so that they go there.
Each item has reference number. Not all objects have reference numbers that are not
1 but it is still quite common and the memory is much bigger these days. This should probably be in the object's memory.
Most objects have no weak references or associated objects. Dedicating space within the object's memory for these would be wasteful. These should be stored externally.
This is the right departure, but it's annoying. For objects that have weak references and related objects, they are quite slow. How can we fix this?
Swift's new implementation of weak references brings the term sidebord .
A sideboard is a separate part of the memory that stores additional information about an object. It is optional which means an object may have a side table or it can not. Objects that require the functionality of a sideboard can cause additional costs, and objects that do not need it do not pay for it.
Each object has a pointer to the side table, and the side table has a pointer back to the object. The sidebar can then store other information, such as the associated object data.
To avoid making eight swaps for the sidebar, Swift makes a nice optimization. Basically, the first word of an object is the class, and the next word stores the reference number. When an object needs a sideboard, the second word is converted into a sideboard instead. Since the item still needs reference numbers, reference counts are stored in the page table. The two cases stand out by placing a little in this field indicating whether it has reference counters or a pointer to the sidebar.
The page table gives Swift the ability to maintain the basic form of the old weak reference system while setting it incorrectly. Instead of pointing to the object, as it used to work, weak references now point directly to the sidebar.
Since the sidebar is known to be small, it's no problem to waste a lot of memory for weak references to large objects so the problem goes away. This also points to a simple solution for the wireless security issue: Not preemptively null out weak references. Since the sidebar is known to be small, weak references to it can stand alone until the references themselves are overwritten or broken.
I should note that the current sidebar implementation only contains reference numbers and a pointer to the original object. Additional uses as associated objects are currently hypothetical. Swift has no built-in lens functionality, and Objective-C API still uses a global table.
The technique has a lot of potential and we will probably see something that associated objects use it for long. I hope this will open the door to stored properties in expansion class types and other great features.
Since Swift is open source, all the code for this content is available.
Most of the sideboard items can be found in stdlib / public / SwiftShims / RefCount.h.
The high weak reference program, along with succulent comments about the system, can be found in fast / stdlib / public / runtime / WeakReference .h.
Some more implementation and comments on how heap-allocated objects work, can be found in stdlib / public / runtime / HeapObject.cpp.
I've linked specific obligations to these files so people can read from the distant future, I can still see what I'm talking about. To see the latest and the best, be sure to switch to the
master branch, or what's relevant to your interests after clicking on the links.
Weak references are an important language function. Swift's original implementation was wonderfully smart and had some nice features but also had some problems. By adding an optional side table, Swift engineers were able to solve these problems while keeping the fine, clear properties of the original. The sideboard implementation also opens many opportunities for great new features in the future.
That's it for today. Come back again for more crazy programming-related ghost stories. Until then, if you have a subject you want to see covered here, please submit it!
Comments RSS feed for this page
Add your thoughts, post a comment:
Spam and off topic posts are deleted without notice. Culprits can be humiliated publicly in my own discretion.