iOS内存管理(弱引用)

1,241 阅读3分钟

准备

这边文章我们继续讲解内存管理系列文章弱引用.平常的开发中我们经常使用__weak修饰符来结果开发过程中的循环引用问题。是因为__weak修饰的对象引用计数不会增加,那么这边文章将从底层源码的角度分析__weak是如何实现的。

断点调试

断点调试 截屏2021-09-25 上午10.37.25.png 总是显示反汇编调试信息debug->show->always show disassembly

截屏2021-09-25 上午10.37.14.png 调用objc_initWeak方法

截屏2021-09-25 上午10.24.14.png 为什么会调用objc_initWeak? 主要是在LLVM编译的时候,会通过__weak匹配到objc_initWeak符号。可以在llvm源码里面验证这一点,如下图

图片1.png

图片2.png

源码实现

在objc源码里搜索objc_initWeak

objc_initWeak

objc_initWeak.png

  • 首先判断调用的对象是否为空,为空直接返回
  • objc_initWeak(&weakObjc,objc),可以直接理解常这样传参
  • 调用storeWeak,这个方法时间上以一个高度封装的方法,objc_destroyWeak销毁的时候同样也会调用.这个方法传了模版参数。

参数说明.png

//haveOld:为true,表示需要被及时清理
//haveNew:为ture,需要一个新的value来替换
//如果crashifdeallocation 是 ture ,那么如果 newObj 是 deallocating,或者 newObj 的类不支持弱引用,则该进程就会停止。
//如果crashifdeallocation 是 false,那么 nil 会被存储。

storeWeak

进入源码:第一步,根据对象获取oldTable合newTable表 截屏2021-09-25 下午12.37.48.png 第二步:对表进行加锁,进行线程安全处理,location 应该与 oldObj 保持一致,如果不同,说明当前的 location 已经处理过 oldObj 可是又被其他线程所修改, 保证线程安全,这个判断用来避免线程冲突重处理问题 截屏2021-09-25 下午12.40.47.png 第三步:确保引用对象的类的初始化已经完成 截屏2021-09-25 下午12.44.12.png 第四步:如果是旧值,从旧值从弱引用表中移除 截屏2021-09-25 下午12.50.16.png 第五步:如果是新值插入对应的弱引用表中,然后通过setWeaklyReferenced_nolock方法标记为对应弱引用对象。

截屏2021-09-25 下午12.53.11.png

weak_register_no_lock

这个方法主要是将弱引用对象插入到对应的弱引用表。

第一步:判断是否是tagged pointer小对象或者nil,如果是直接返回。

截屏2021-09-25 下午12.59.58.png

第二步:判断对象是否正dealloc,确保对象可用 截屏2021-09-25 下午1.04.27.png 第三步:进行添加操作

截屏2021-09-25 下午1.07.10.png 这里有一个判断,如果之前以前存在对应的entry,则直接添加。如果没有则创建后在添加。

append_referrer(添加)

第一步:先存储到inline里面 截屏2021-09-25 下午1.32.20.png 第二步,如果inline存满了,存储到outline,并且把inline数据的也存储到outline中 截屏2021-09-25 下午1.39.05.png 第三步:outline扩容,达到容量的3/4时候扩容

截屏2021-09-25 下午1.41.09.png

弱引用的释放

上篇文章 iOS内存管理(Nonpointer_isa+散列表+retain+release)提到过对象的释放,实际上对象有一个弱引用的标识符weakly_referenced,来区分 objc_clear_deallocating->clearDeallocating

截屏2021-09-25 下午1.46.02.png 调用weak_clear_no_lock

截屏2021-09-25 下午1.47.50.png

弱引用的结构图

下面用一张图来总结,弱引用表的结构,便于理解

截屏2021-09-25 下午2.09.36.png

  • 首先有一个全局的变量,里面有8个sideTable(真机上)。通过object对象可以找到对应的sideTabe
  • sideTable 里面有一个weak_table_t.weak_table_t里面存储了一个weak_entry_t的数组,可以通过object拿到对应的weak_entry_t。一个object对象和一个weak_entry_t对应
  • 一个对象可能有多个弱引用,弱引用对象就存储在weak_entry_tinline或者outline里面

总过上面的一个结构图我相信大家对弱引用的了解更加全面,这样更有利于我们对源码的理解。