内存管理(四)引用计数与weak
00 分钟
2020-10-13
2020-10-13
type
status
date
slug
summary
tags
category
icon
password
在前面的文章中,已经对引用计数以及其在开发中的使用做了初步了解。在本篇中,我们将会深入阐述苹果对引用计数这个技术的底层实现。
本文涉及到的objc源码,来自于objc源码,版本是723,文中涉及大量源码,均做删减,主要对加锁部分进行删减。
导读:
  1. 对源码解读部分,若觉得源码冗余,每一步解读最后都有总结,可直接看总结。
  1. 第五部分-图总结了引用计数相关的图。

一、引用计数的存储

我们知道,对于纯量类型的变量,是没有引用计数的,因为不是对象,其申请的变量存储在栈上,由系统来负责管理。
另外一种类型,是前面讲过的Tagged Pointer小对象,包括NSNumberNSStringNSDate等几个类的变量。它们也是存储在栈上,当然也没有引用计数。
整理了下面表格:
notion image
关于对象类型的引用计数,其存在的地方有两个:
notion image

1.1 isa指针里的引用计数

首先,我们来观察对象类型中存放在优化后的isa指针,下面是出现过多次的isa指针布局:
notion image

1.2 Side Table里的引用计数

Side Table在系统中的结构如下:
notion image
而每一张Side Table中针对引用计数的部分如下:
notion image

二、引用计数管理

在了解了引用计数存储的地方之后,对引用计数管理的理解就更方便了。

2.1 管理引用计数的方法

notion image
下面,针对上面的方法,根据源码,进行一定的追踪。

2.2 retainCount

后续引用计数相关方法,只看优化过的指针,即只针对64位进行描述。
根据源码,其调用轨迹如下:
NSObject.mm
━retainCount()
┗━ rootRetainCount()
┗━ rootRetainCount()

retainCount总结

notion image
其中,针对后两种情况:
notion image
对于存在于Side Table中的引用计数,需要注意,其最低2位被占用,所以取出来,要右移2位。

2.3 retain

源码调用路径如下:
NSObject.mm
━retain()
┗━objc_retain()
┗━obj->retain()
┗━rootRetain()

retain总结:

Tagged Pointer对象,没有retain。
isa中extra_rc若未溢出,则累加1。如果溢出,则将isa和side table对半存储。
notion image

2.4 release

源码调用路径:
NSObject.mm
━release()
┗━ objc_release()
┗━ obj->release()
┗━ rootRelease()
下面是release方法的主要执行流程:

release总结:

notion image

三、对象的销毁

3.1 dealloc方法

notion image

3.2 dealloc重写

notion image

3.3 dealloc源码

源码的执行流程如下:
━ dealloc
┗━_objc_rootDealloc —— <NSObject.mm>
┗━ rootDealloc —— <objc-object.h>
┗━ object_dispose —— <objc-runtime-new.mm>
┗━ objc_destructInstance、free  —— <objc-runtime-new.mm>
我们跟踪方法rootDealloc
下面是具体销毁对象的流程:
是的,下一步就是进入clearDeallocating()方法。

四、weak

weak有一个特性,在对象销毁的时候,指向该对象所有的weak指针都会置为nil,那么这个特性是如何在dealloc方法里体现的。

4.1 weak指针存储对象结构

要了解weak指针的处理,先要了解其对象结构。
weak指针存储在一个个Side Table对象中的weak_table,这是一张hash表。
之后,在weak_table中,存储着一个个对象的entry表,这也是个hash表,每个entry就存储着要销毁对象的所有弱引用地址。
Side Table在系统有一组,可根据对象地址获取其对应的SideTable。
如下图所示:
notion image

4.2 weak指针存储的hash表

上面说道weak指针的对象结构,如下图,展示的是weak指针如何通过hash表串联起来,进行存储的。
notion image

4.3 源码

下面,我们就继续跟踪上面说到的clearDeallocating()方法,根据优化过的isa指针,其中调用的:
━ clearDeallocating()   —— <objc-object.h>
┗━ clearDeallocating_slow()  —— <NSObject.mm>
更进一步,看看是如何清空weak指针的。

weak指针处理总结:

notion image

五、图

5.1 对象结构图

notion image

5.2 存储图

notion image

参考

链接

  1. Advanced Memory Management Programming Guide
  1. Memory Management Programming Guide for Core Foundation
  1. Automatic Reference Counting
  1. Objective-C Automatic Reference Counting (ARC)
  1. Friday Q&A 2010-07-16: Zeroing Weak References in Objective-C
  1. Friday Q&A 2017-09-22: Swift 4 Weak References
  1. runtime 如何实现 weak 属性
  1. Objective-C 引用计数原理
  1. iOS管理对象内存的数据结构以及操作算法--SideTables、RefcountMap、weak_table_t-一
  1. iOS管理对象内存的数据结构以及操作算法--SideTables、RefcountMap、weak_table_t-二
  1. objc源码