对于C或者C++的开发来说,大家都知道最麻烦的地方就是指针的操作,尤其是指针引起的内存泄漏问题更是一个痛点。当前对于java来说,由于没有了指针,相对来说会好一些,但是这是由于JVM已经代替我们处理了很多情况,JVM本身也是由C/C++来开发的,所以最终其实对于指针的操作还是绕不过去的。
Android的应用可以用java开发,但是底层很多的地方都是用C/C++来开发的,包括HAL和framework的C++部分,所以android提供了智能指针来帮助开发者避免没有及时清理对象而引起的OOM问题。
智能指针主要分三种,轻量级指针,强指针,弱指针。他们总体的设计思路都是一样的,即三种都有一个基本,所有需要使用智能指针的对象都需要继承这个基类,这个基类中提供了计数器,计数器表示该对象被引用的次数。
另外有个智能指针的类,这个类中有个变量保存着具体的对象,这个类是操作具体对象计数器的,一旦这个类被销毁后,他会根据情况判断是否需要销毁掉具体的对象。而对于我们开发者来说,只需要使用具体的对象就可以,不需要管对象的生命周期了,这样就达到了自动销毁不使用对象的目的。下面我们就开始具体的介绍。
一. 轻量级指针
轻量级指针的基类代码如下
```c++
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
inline int32_t getStrongCount() const {
return mCount;
}
protected:
inline ~LightRefBase() { }
private:
mutable volatile int32_t mCount;
};
```
可以看到轻量级指针对象基类还是比较简单的,它有一个私有变量mCount,记录了这个对象被引用的次数。在构造方法中被初始化为0。
他有3个主要的方法,分别是incStrong,decStrong,getStrongCount,从名字就可以很容易看出,分别是对变量mCount加1,减1和获取变量mCount的值。
这里要注意的是decStrong方法中,android_atomic_dec方法的返回值是减1之前的值,所以这里的if (android_atomic_dec(&mCount) == 1)的意思是,如果减去1后,mCount等于0了,即没有被其他引用了,就会释放自己,这样就达到了销毁无用对象的左右。这里的方法都是通过智能指针来执行的,下面看下智能指针类是怎么样的。
```c++
template <typename T>
class sp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (U* other);
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
// Reset
void clear();
// Accessors
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
// Operators
COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
// Optimization for wp::promote().
sp(T* p, weakref_type* refs);
T* m_ptr;
};
```
这个是强引用智能指针的全部,我们现在先说轻量级指针用到的,所以下面我把上面这个类精简下
```c++
template <typename T>
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
~sp();
private:
T* m_ptr;
};
```
可以看到经过精简后,其实轻量级的智能指针也是比较简单的。它是一个模版类,这个泛型T其实就是指向引用对象的类型。它有一个私有变量m_ptr,默认的构造函数它是指向0的,表示没有引用对象。然后看他其他2个构造函数的实现:
```c++
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);
}
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) m_ptr->incStrong(this);
}
```
可以看到2个构造函数,一个参数是引用对象T,另一个是拷贝构造函数,参数是另一个sp,他们最终都是执行了把对象赋值给sp的变量m_ptr,然后执行对象基类中的incStrong,即把对象中计数器+1。在看一下他的析构函数
```c++
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
```
这里也很好理解,就是执行对象基类的decStrong函数。根据前面介绍的对象基类LightRefBase,只要引用为0了,就会自动销毁对象。
以上这些就是轻量级智能指针的整体架构了,应该还是比较好理解的。下面举个例子来说明下,通过使用过程来加深理解。
先上代码:
```c++
class LightClass : public LightRefBase<LightClass>
{
public:
LightClass()
{
printf("Construct LightClass Object.\n");
}
virtual ~LightClass()
{
printf("Destory LightClass Object.\n");
}
};
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;
}
```
这里首先new一个对象LightClass,LightClass继承了前面说的基类LightRefBase,所以它是一个可以被轻量级指针使用的对象。然后我们创建一个智能指针lpOut指向这个对象,这个时候printf语句会打印出这个对象引用次数是1.
接下来我们在块作用域中再创建一个智能指针指向前面创建的这个智能指针,由构造函数可以知道他是一个拷贝构造函数,实际是会指向LightClass类,所以这个时候printf打印出的对象引用次数会是2.
当出了块作用域后,我们再次执行printf语句,由于智能指针lpInner的作用域是块里面,现在出了块后会执行析构函数,所以printf打印会变回1.
最后当main函数执行完毕后,智能指针lpOut的析构函数会被再次打印,从而会调用到LightRefBase基类中decStrong方法,最终会自动销毁LightClass。
整个这个就是使用轻量级智能指针的过程,应该还是比较好理解。 轻量级指针就介绍到这里,后面会继续说其他两个智能指针。
Android的智能指针之轻量级指针