Swift源码解析之弱引用

2020-01-09 00:12:25王冬梅

到这里大家发现一个问题没有,被引用对象释放了为什么还能直接访问 Side Table?其实 Swift ABI 中 Side Table 的生命周期与对象是分离的,当强引用计数为 0 时,只有 HeapObject 被释放了。

只有所有的 weak 引用者都被释放了或相关变量被置 nil 后,Side Table 才能得以释放,相见:


void HeapObjectSideTableEntry::decrementWeak() {
 // FIXME: assertions
 // FIXME: optimize barriers
 bool cleanup = refCounts.decrementWeakShouldCleanUp();
 if (!cleanup)
 return;

 // Weak ref count is now zero. Delete the side table entry.
 // FREED -> DEAD
 assert(refCounts.getUnownedCount() == 0);
 delete this;
}

所以即便使用了弱引用,也不能保证相关内存全部被释放,因为只要 weak 变量不被显式置 nil,Side Table 就会存在。而 ABI 中也有可以提升的地方,那就是如果访问弱引用变量时发现被引用对象已经释放,就将自己的弱引用销毁掉,避免之后重复无意义的 CAS 操作。当然 ABI 不做这个优化,我们也可以在 Swift 代码里做。:)

总结

以上就是 Swift 弱引用机制实现方式的一个简单的分析,可见思路与 Objective-C runtime 还是很类似的,都采用与对象匹配的 Side Table 来维护引用计数。不同的地方就是 Objective-C 对象在内存布局中没有 Side Table 指针,而是通过一个全局的 StripedMap 来维护对象和 Side Table 之间的关系,效率没有 Swift 这么高。另外 Objective-C runtime 在对象释放时会将所有的 __weak 变量都 zero-out,而 Swift 并没有。

总的来说,Swift 的实现方式会稍微简单一些(虽然代码更复杂,Swift 团队追求更高的抽象)。第一次分析 Swift ABI,本文仅供参考,如果存在错误,欢迎大家勘正。感谢!

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对ASPKU的支持。