为了能够自动回收C++的对象, google使用sp与wp两个模板类使用引用计数的方式自动对C++对象进行回收, 作为阅读Android C/C++源码必要的基础, 从源码角度剖析下实现原理
数据结构
RefBase是所有引用计数gc对象的基类, 引入了一个内部属mRefs进行状态维护。 其内部属属性为:
std::atomic<int32_t> mStrong;
std::atomic<int32_t> mWeak;
RefBase* const mBase; // 指向外部类
std::atomic<int32_t> mFlags;
其中mFlags表示为改对象的生命状态: OBJECT_LIFETIME_STRONG(0x0000), OBJECT_LIFETIME_WEAK(0x0001) 初始值是0, 也即是说整个对象默认是强引用计数.
mStrong初始值是(1<<28)一个很大的数字, 代表强引用数量. mWeak初始值为0, 代表弱引用数量.
算法
各属性值的关键节点与描述
No | mStrong | mWeak | mFlags | Description |
1 | 0x10000000000000 | 0 | 0 | 初始状态 |
2 | 1 | 1 | 0 | 调用incStrong |
3 | 0 | 1 | 0 | 调用incWeak |
4 | 1 | 2 | 0 | attemptIncStrong |
算法在实现过程中, 考虑到了多线程与多CPU架构下对计算指令的影响, 所以使用std::atomic这个原子整数. 算法比较简单:
incStrong
强引用计数+1时, 弱引用计数+1
- 调用mRefs.incWeak()
- mStrong值加1,并获取mStrong的老值, 如果mStrong的老值不是1 << 28则结束
- 将mStrong值置为1, 并调用onFirstRef
从初始状态(No.1) 调用incStrong后变成状态(No.2)
decStrong
强引用计数-1时, 弱引用计数-1, 弱此时是强引用计数模式, 且强引用计数为0, 回收该对象
- mStrong值减1, 并获取老值
- 若老值为1, 调用onLastStringRef, 如果flags 包含了OBJECT_LIFETIME_STRONG时, delete this.
- 调用mRefs.decWeak()
从状态No.2 –> No.1
attemptIncStrong(weakref_type)
首先弱引用计数加1, 尝试强引用计数+1, 如果此时是弱引用计数模式, 会调用onIncStrongAttempted来请示是否允许强引用加1
- 调用incWeak
- 获取mStrong值, 如果存在有效mStrong, 加1, 结束
- 如果flags为Strong时, mStrong加1, 如果不是Strong, 则进行尝试自救onIncStrongAttempted
调用此函数之前, case为No.3, 调用之后, case为No.4
mRefs.incWeak
mWeak值加1, 从原始状态(No.1)调用incWeak后变成状态(No.3)
mRefs.decWeak
- mWeak值减1, 如果mWeak不为0则返回
- 如果flags包含OBJECT_LIFETIME_STRONG: delete mRefs引用(这里需要结合RefBase的析构函数)
- 如果flags不包含OBJECT_LIFETIME_STRONG: 调用onLastWeakRef, delete RefBase
sp与wp
强引用sp
核心属性: m_ptr: RefBase的对象指针
- 构造时调用RefBase的incStrong
- 析构时调用RefBase的decStrong
于此同理wp实现类似, 均将实现代理给了RefBase中
由弱生强 promote():
直接调用m_refs的attemptIncStrong:
生死魔咒 extendsObjectLifetime(int32_t)
这里进行设置flags属性罢了