对象的维护
在编程中,维护对象的生命周期的方式有两种方式:
- 可达性算法
- 引用计数算法
Java通过可达性管理对象的生命周期GC可达性实践-内存泄露分析。而C++中由于没有GC的机制,通常使用的是引用计数算法。
简单的引用计数通常是给对象添加一个引用计数器,当有引用时,计数器加1,当引用失效时,引用计数减少1,当计数器为0时,说明可以回收对象了。但是此种方式无法解决循环引用的情况。
如图:
A对象引用了B对象,B对象引用了A对象。由于A,B的对象的计数器均不为0,因此永远不会回收A,B对象。
为了解决这个问题,引入了强引用计数和弱引用计数。存在强引用,对象不会回收,但只存在弱引用,对象是可以回收的。对于上面的循环引入强,弱引用,就是下面的情况。
A强引用B,B弱引用A,由于A只有弱引用,A是可以回收的,一旦A回收,无对象强引用B,B也可以回收了,通过强,弱引用就解决了引用计数算法中的循环引用的问题。
Android中的智能指针
Android为C++提供了三种智能指针
- 轻量级指针(sp,LightRefBase),使用简单的引用计数,也就是只有强引用计数。
- 强引用指针(sp,RefBase),使用强引用计数
- 弱引用指针(wp,RefBase),使用弱引用计数
轻量级指针 - LightRefBase
需要使用轻量级指针的类继承LightRefBase
就可以了。LightRefBase
是一个模板类,仅仅实现了简单的引用计数逻辑。
mCount
计数器incStrong
添加强引用计数的方法decStrong
减少强应用计数的方法,并且在计数器为0时,删除对象。
class LightClass : public LightRefBase<LightClass> {
};
LightClass
简单继承LightRefBase
。
然后通过sp
来完成引用计数。
int main(int argc, char** argv)
{
LightClass* pLightClass = new LightClass();
sp<LightClass> lpOut = pLightClass;
printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
{
sp<LightClass> lpInner = lpOut;
printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
}
printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
return 0;
}
sp类比较简单,强引用计数的操作是在构造方法和析构方法中。
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);
}
构造方法中初始化m_ptr
为传递的对象,并调用传递的对象的incStrong
方法来添加强引用计数。也是我们传递的LightRefBase
的子类。
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
析构方法中调用incStrong
来较少强引用计数。
基本交互图:
强引用,弱引用原理
强弱引用的原理是三个重要的类
RefBase
: 实现了强引用,弱引用计数wp
: 弱引用指针sp
:强引用指针
RefBase
实现了强引用,弱引用计数,要分析强引用,弱