GVKun编程网logo

套接字 – 带addrinfo结构的智能指针(套接字实现原理)

16

如果您对套接字–带addrinfo结构的智能指针和套接字实现原理感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解套接字–带addrinfo结构的智能指针的各种细节,并对套接字实现原理进行深入的分

如果您对套接字 – 带addrinfo结构的智能指针套接字实现原理感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解套接字 – 带addrinfo结构的智能指针的各种细节,并对套接字实现原理进行深入的分析,此外还有关于Android 中的智能指针、Android 系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析、android中的智能指针、Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析的实用技巧。

本文目录一览:

套接字 – 带addrinfo结构的智能指针(套接字实现原理)

套接字 – 带addrinfo结构的智能指针(套接字实现原理)

我需要处理两个struct addrinfo指针.因为我用C(11)编码,所以我要使代码异常安全.实际上,我的结构可能会抛出runtime_error.
当你不再需要那种结构时,你应该调用freeaddrinfo来释放结构中的列表.请考虑以下代码:

#include <memory>
#include <netdb.h>

class SomeOtherClass
{
  public:
    SomeOtherClass() : hints(new addrinfo),result(new addrinfo) { /*stuff*/ }
    ~SomeOtherClass() { freeaddrinfo(result.get()); } // bad things will happen

private:
    std::unique_ptr<addrinfo> hints,result;
};

class MyClass : public SomeOtherClass
{
public:
    MyClass() { /* hints initialization,call to getaddrinfo,etc. */ }

private:
    // ...
};

我的问题是:

> addrinfo是一个“旧的”C结构,没有ctor / dtor可以调用:使用new是否安全?
> getaddrinfo需要一个指向addrinfo结构指针的指针:我应该如何通过智能指针传递它?
>如何调用freeaddrinfo?删除(或更好地释放)智能指针所持有的指针被认为是不安全的.

对于提示没有问题,因为它的寿命较短.

解决方法

对于您自己分配的任何addrinfo,使用new和delete是安全的,因此您可以使用unique_ptr的默认实现来处理它.

对于getaddrinfo()分配的任何addrinfo,您必须使用freeaddrinfo()来释放它.您仍然可以使用unique_ptr,但必须将freeaddrinfo()指定为自定义Deleter,例如:

class SomeOtherClass
{
  public:
    SomeOtherClass() : hints(new addrinfo),result(nullptr,&freeaddrinfo) { /*stuff*/ }

private:
    std::unique_ptr<addrinfo> hints;
    std::unique_ptr<addrinfo,void(__stdcall*)(addrinfo*)> result;
};

然后你可以这样做:

getaddrinfo(...,&result);

或者,如果std :: unique_ptr没有覆盖&操作符:

addrinfo *temp;
getaddrinfo(...,&temp);
result.reset(temp);

更新:更好的选择是使用decltype并让编译器为您推导出Deleter的函数类型:

std::unique_ptr<addrinfo,decltype(&freeaddrinfo)> result;

Android 中的智能指针

Android 中的智能指针

Android 中提供了三种智能指针:
① 轻量级指针(sp + LightRefBase):简单的引用计数,只使用强引用计数。
② 强引用指针(sp + RefBase):使用强引用计数。
③ 弱引用指针(wp + RefBase):使用弱引用计数。

一、轻量级指针

引用计数的最简单的思路是:使用一个计数器来记录一个对象被引用的次数。每当有引用指向对象时,计数器加 1;每当一个指向对象的引用断开时,计数器减 1。当计数器减为 0 时,就自动释放该对象的内存空间。

首先,每个对象都需要关联一个计数器,简单的实现方案是将计数器定义在基类中,这样所有的类继承该基类的类都有了计数器。

看看在 android 中是怎么定义这个基类的:

// frameworks/base/include/utils/RefBase.h
template <class T>
class LightRefBase {
public:
    inline LightRefBase() : mCount(0) { }
    
    // 计数器加1
    inline void incStrong(const void* id) const {
        android_atomic_inc(&mCount);
    }
    
   // 计数器减1 
   inline void decStrong(const void* id) const {
        if (android_atomic_dec(&mCount) == 1) {
            // 当计数器减到0时,析构自己
            delete static_cast<const T*>(this);
        }
   }
   
protected:
   inline ~LightRefBase() { }
   
private:
    mutable volatile int32_t mCount; // 32位的计数器
}

这个类封装了计数器,提供了对计数器的操作接口(incStrongdecStrong)。其中 android_atomic_inc()android_atomic_dec() 都是原子操作,返回的是加 1 或减 1 之前的计数值。

那谁去操作计数器加 1 还是减 1 呢?sp 类就是干这个事的。

// frameworks/base/include/utils/StrongPointer.h
template <typename T>
class sp
{
public:
    sp(T* other);
    ~sp();
    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
   inline  T&      operator* () const  { return *m_ptr; }
   inline  T*      operator-> () const { return m_ptr;  }
   ...
private:
   T* m_ptr;
}

可以看到,sp 类包含 m_ptr 指针成员,并重载了 * 运算符和 -> 运算符,是一个智能指针。由于它只用于强引用计数,因此这里的 sp 的实际含义是强指针(Strong Pointer)。

下面我们看下,sp 是如何操作计数器加 1、减 1 和释放被引用对象的。

template<typename T>
sp<T>::sp(T* other) : m_ptr(other)
{
    // 在sp构造函数中,对指向的对象的引用计数加1
    if (other) other->incStrong(this);
}
template<typename T>
sp<T>::~sp()
{
    // 在sp析构函数中,对指向的对象的引用计数减1
    // 析构对象的逻辑在decStrong()里
    if (m_ptr) m_ptr->decStrong(this);
}

有一个要注意的点就是,sp 在被创建后,是可以指向另一个对象的。如下图所示:

指向另一个对象

因此要重载赋值操作符

template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
    // 对新引用的对象的计数器加1
    if (other) other->incStrong(this);
    // 由于不再引用原来的对象,则原有对象的计数器减1
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

二、弱引用计数的引入

上述引用计数的方案虽然实现简单,但存在一个很大的问题,就是循环引用。如下图:

循环引用

由于 A 和 B 相互引用对方,导致彼此的计数器值都是 1,无法被释放,但 A 和 B 都没有被其他对象引用。

为了解决循环引用,android 中提供了弱引用指针。

强引用和弱引用

基本思想是:
① 循环引用时,选择一强一弱。
② 当强引用计数减为 0 时,不管弱引用计数是否为 0,都释放对象。
③ 不能使用弱引用指针直接操作对象的函数。(避免对象被释放后,弱引用还持有对象的引用,这时操作对象就是错误的)
④ 弱引用指针要想操作对象,必须先提升为强引用指针,如果提升成功,才能对对象进行访问。(强引用指针重载了 * 和 -> 运算符,而弱引用指针则没有重载)

在这种方案中,每个对象需要有两个计数器,一个是强引用计数器,一个是弱引用计数器。看看 android 中的实现:

// frameworks/base/include/utils/RefBase.h
class RefBase {
public:
    // 强引用计数器加1
    void incStrong(const void* id) const;
    // 强引用计数器减1
    void decStrong(const void* id) const;
    weakref_type* createWeak(const void* id) const;
    
   class weakref_type {
       // 弱引用计数器加1
       void incWeak(const void* id);
       // 弱引用计数器减1
       void decWeak(const void* id);
   }
protected:
    RefBase();
    virtual ~RefBase();
private:
    weakref_impl* const mRefs;
}
// frameworks/base/include/utils/RefBase.cpp
class RefBase::weakref_impl : public RefBase::weakref_type {
public:
    volatile int32_t    mStrong; // 强引用计数器
    volatile int32_t    mWeak; // 弱引用计数器
    RefBase* const      mBase; // 被引用的对象
    volatile int32_t    mFlags; // 回收对象的标识

    weakref_impl(RefBase* base)
        // FIRST_INC_STRONG = 0x0001 用来表示是不是第一次
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0) {}
}

这几个类之间的关系如下图:

RefBase 类和 weakref_impl 类是双向关联关系:

  • RefBase 对象包含 weakref_impl 对象,计数器在 weakref_impl 对象中。
  • weakref_impl 对象包含 RefBase 对象,在弱引用计数方式下,当弱引用计数减为 0 时,需要释放 RefBase 对象。

三、强引用指针

sp 类前面已经提到了,当构造 sp 对象会调用其指向对象的 incStrong() 函数,而析构 sp 对象时,会调用其指向对象的 decStrong() 函数。 轻量级指针是使用 sp + LightRefBase。而强引用指针则是使用 sp + RefBase。在这种方式下,则会调用 RefBase 的 incStrong()decStrong()

// frameworks/base/include/utils/RefBase.cpp
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id); // 弱引用计数加1
    
    // 强引用计数加1
    const int32_t c = android_atomic_inc(&refs->mStrong);

    if (c != INITIAL_STRONG_VALUE)  { // 如果不是第一次增加计数值
        return;
   }

   // 由于mStrong的初始值是INITIAL_STRONG_VALUE,
   // 因此需要减去INITIAL_STRONG_VALUE计数值才能正确
   android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
   refs->mBase->onFirstRef(); // 第一次增加计数值会触发这个调用
}
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    // 强引用计数减1
    const int32_t c = android_atomic_dec(&refs->mStrong);

    if (c == 1) { // 如果强引用计数减为0
        refs->mBase->onLastStrongRef(id);
        // 默认模式是OBJECT_LIFETIME_STRONG
       if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
           // 如果是OBJECT_LIFETIME_STRONG模式,则析构该对象
           delete this;
       }
   }
   // 弱引用计数减1
   refs->decWeak(id);
}

上面代码可以看出,在 RefBase 对象被引用时,其强引用计数器和弱引用计数器都加 1;当 sp 析构时,将所引用的 RefBase 对象的强引用计数器和弱引用计数器都减 1。当强引用计数减到 0 时,会析构 RefBase 对象(OBJECT_LIFETIME_STRONG 模式)。
使用 sp + RefBase 的这种方式,强引用计数值等于弱引用计数值。

RefBase 对象的销毁逻辑我们清楚了,但是还有一个问题,weakref_impl 对象是什么时候创建和析构的呢?

RefBase::RefBase()
    : mRefs(new weakref_impl(this)) // RefBase的构造函数中创建了weakref_impl
{
}
RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        // 没有使用过任何强引用指向过它,则直接析构weakref_impl
        delete mRefs;
    } else {
        // 目前我们讨论的强引用指针不会走进下面的if语句里
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            if (mRefs->mWeak == 0) {
                delete mRefs;
            }
       }
   }
   // for debugging purposes, clear this.
   const_cast<weakref_impl*&>(mRefs) = NULL;
}

我们发现,在有使用过强引用指向 RefBase 对象后,当强引用计数减为 0 时,RefBase 对象被析构,但它的析构函数中没有看到析构 weakref_impl 对象。那么 weakref_impl 对象是在哪里被析构的呢?答案在 RefBase::weakref_type::decWeak() 函数中。

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    // 弱引用计数减1
    const int32_t c = android_atomic_dec(&impl->mWeak);
    if (c != 1) return;
    
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
           delete impl->mBase;
       } else {
           delete impl; // 析构自己
       }
   } else {
       ...
   }
}

总结一下 weakref_type 对象被析构的时机和位置:

① 如果 RefBase 对象从未被 sp 对象引用,则在 RefBase 类的析构函数中析构 weakref_type 对象。
② 如果 RefBase 对象被 sp 对象引用过,则在 RefBase 对象的弱引用计数器减为 0 时,weakref_type 对象自己析构自己。

四、弱引用指针

上面的几种方式,都是只有强指针的情况。如果只有弱指针或强弱指针都有的情况呢?

我们先来看看弱指针的定义:

// frameworks/base/include/utils/RefBase.h
template <typename T>
class wp
{
public:
    inline wp() : m_ptr(0) { }
    wp(T* other);
    wp(const wp<T>& other);
    ~wp();
    
   wp& operator = (T* other);
   wp& operator = (const wp<T>& other);
   // 提升为强指针
   sp<T> promote() const;
   
private:
   T* m_ptr;
   weakref_type* m_refs;
}

下图给出了 wp、RefBase 和 weakref_type,这三个类之间的关系:

template<typename T>
wp<T>::wp(T* other) : m_ptr(other)
{
    // 将wp所引用对象的弱引用计数加1
    if (other) m_refs = other->createWeak(this);
}

RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
     // 将弱引用计数加1
    mRefs->incWeak(id);
    return mRefs; // 返回构造函数时创建的weakref_impl对象
}

template<typename T>
wp<T>::~wp()
{
    // 析构wp时,将所引用对象的弱引用计数减1
    if (m_ptr) m_refs->decWeak(this);
}

由上面代码可知,使用 wp + RefBase,只会增加或减少对象的弱引用计数。

如果只有弱引用,RefBase 什么时候被析构?weakref_impl 对象什么时候被析构? 这里需要先说明 mFlags 的两种值:

  • OBJECT_LIFETIME_STRONG:对象只受强引用控制,一旦强引用计数为 0,就可以回收对象。
  • OBJECT_LIFETIME_WEAK:对象受弱引用控制,强引用计数为 0,而弱引用计数不为 0 的时候,实际对象不会被回收;只有当强引用计数和弱引用计数同时为 0 时,实际对象才会被回收。
void RefBase::weakref_type::decWeak(const void* id) {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    if (c != 1) return;
    
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
             // 说明对象没有被强引用引用过,只有弱引用引用过它
             // 这种情况下,弱引用计数减为0时,析构RefBase对象
            delete impl->mBase;
        } else {
            delete impl;
       }
   } else {
       if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
           // 对象受弱引用控制,当弱引用计数为0时,析构RefBase对象
           delete impl->mBase;
       }
   }
}

而在 RefBase 对象的析构函数中,在没有被强引用指针引用过的情况下,会析构 weakref_impl 对象。

RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        // 没有使用过任何强引用指向过它,则直接析构weakref_impl
        delete mRefs;
    } else {
        ...
    }
}

五、既使用了强引用指针,又使用了弱引用指针

每创建一个 sp 指向 RefBase 对象,对象的强引用计数会加 1,弱引用计数也会加 1。
每创建一个 wp 指向 RefBase 对象,只会对对象的弱引用计数加 1。
由此可知,当同时使用了强引用指针和弱引用指针,弱引用计数的值 > 强引用计数的值。

而析构 RefBase 对象和 weakref_impl 对象的时机和位置分两种情况:
1. 对象回收受强引用控制(mFlags 为 OBJECT_LIFETIME_STRONG)

void RefBase::decStrong(const void* id) const {
    weakref_impl* const refs = mRefs;
    const int32_t c = android_atomic_dec(&refs->mStrong);
    
    if (c == 1) {
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            // 对象回收受强引用控制
            // 当强引用计数减为0时,不管此时弱引用计数是否为0,都析构RefBase对象
           delete this;
       }
    }
    refs->decWeak(id); // 弱引用计数减1
}
void RefBase::weakref_type::decWeak(const void* id) {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    // 如果强引用计数已经减为0,RefBase被析构,但弱引用计数此时>0,
    // 这时decWeak()并不析构weakref_impl对象
    // 即weakref_impl对象可以比RefBase对象生命周期长
    if (c != 1) return;
    
    // 当已有的wp对象析构后,最终会将弱引用计数减为0
   if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
       if (impl->mStrong == INITIAL_STRONG_VALUE) {
           // 不会走这里,这里是只使用弱引用指针的情况
           delete impl->mBase;
       } else {
           // 对象回收受强引用控制
           // 弱引用计数减为0,则析构weakref_impl对象
           delete impl;
       }
   } else {
       ...
   }
}

2. 对象回收受弱引用控制(mFlags 为 OBJECT_LIFETIME_WEAK)

void RefBase::decStrong(const void* id) const {
    weakref_impl* const refs = mRefs;
    // 就算强引用计数减为0,也不会析构RefBase对象
    const int32_t c = android_atomic_dec(&refs->mStrong);
    
    ...
    
    refs->decWeak(id); // 弱引用计数减1
}
void RefBase::weakref_type::decWeak(const void* id) {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    if (c != 1) return;
    
    // 当已有的wp对象析构后,最终会将弱引用计数减为0
   if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
       ...
   } else {
      // 对象回收受弱引用控制
      // 当弱引用计数减为0时,才去析构RefBase对象,调用RefBase的析构函数 
      delete impl->mBase;
  }
}
RefBase::~RefBase() {
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
        ...
    } else {
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            if (mRefs->mWeak == 0) {
                // 在RefBase的析构函数中,才去析构weakref_impl对象
                delete mRefs;
            }
        }
    }
}

参考

  • 《Android 系统源代码情景分析》
  • 《深入理解 Android 内核设计思想 第 2 版》

Android 系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

Android 系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

这是一篇对 Android 的垃圾管理机制分析比较透彻的一篇文章。

android中的智能指针

android中的智能指针

智能指针简介

    在使用C++来编写代码的过程中,经常出现内存泄漏和野指针问题。为了避免出现上述问题,一般的做法就是使用引用计数的方法:

   每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了。

    但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,易出错。这时候,智能指针就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。(一下子可能很难理解,跳过,看完例子再回来理解这段话!!

    在计算机科学领域中,提供垃圾收集(Garbage Collection)功能的系统框架,即提供对象托管功能的系统框架,例如Java应用程序框架,也是采用上述的引用计数技术方案来实现的,然而,简单的引用计数技术不能处理系统中对象间循环引用的情况。

    考虑这样的一个场景,系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏。这样,就要采取另外的一种引用计数技术了,即对象的引用计数同时存在强引用和弱引用两种计数,当父对象要引用子对象时,就对子对象使用强引用计数技术,而当子对象要引用父对象时,就对父对象使用弱引用计数技术,而当垃圾收集系统执行对象回收工作时,只要发现对象的强引用计数为0,而不管它的弱引用计数是否为0,都可以回收这个对象,但是,如果我们只对一个对象持有弱引用计数,当我们要使用这个对象时,就不直接使用了,必须要把这个弱引用升级成为强引用时,才能使用这个对象,在转换的过程中,如果对象已经不存在,那么转换就失败了,这时候就说明这个对象已经被销毁了,不能再使用了。

 

Android中的智能指针

    说到智能指针,熟悉c++的朋友知道,c++默认提供了一套默认指针的实现,auto_ptr, shared_ptr, weak_ptr, unique_ptr。其中auto_ptr是c++中最早的智能指针实现,但是具有很大的局限性,所以在c++11中启用了auto_ptr,而改用后面三种智能指针。

    讲道理,c++11提供的智能指针很优秀,并不比android中实现的智能指针方案差,那么为什么android要自己实现一套智能指针呢?纯属个人分析,在android早起版本时c++11规范并没有出来,但是开发者不满意auto_ptr表现,所以自己实现了一套智能指针。等到c++11规范出来的时候,android已经成型,太多地方用到了智能指针,所以修改复杂,于是就不改了……猜测不知道对错,但是有一点肯定的是,绝对不是android底层不能使用c++11,因为最新版(android 8)的android智能指针实现代码里使用了c++11的内容。

    回到主题Android的智能指针:

    Android系统提供了强大的智能指针技术供我们使用,这些智能指针实现方案既包括简单的引用计数技术,也包括了复杂的引用计数技术,即对象既有强引用计数,也有弱引用计数,对应地,这三种智能指针分别就称为轻量级指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Weak Pointer)。无论是轻量级指针,还是强指针和弱指针,它们的实现框架都是一致的,即由对象本身来提供引用计数器,但是它不会去维护这个引用计数器的值,而是由智能指针来维护,就好比是对象提供素材,但是具体怎么去使用这些素材,就交给智能指针来处理了。由于不管是什么类型的对象,它都需要提供引用计数器这个素材,在C++中,我们就可以把这个引用计数器素材定义为一个公共类,这个类只有一个成员变量,那就是引用计数成员变量,其它提供智能指针引用的对象,都必须从这个公共类继承下来,这样,这些不同的对象就天然地提供了引用计数器给智能指针使用了。总的来说就是我们在实现智能指会的过程中,第一是要定义一个负责提供引用计数器的公共类,第二是我们要实现相应的智能指针对象类,后面我们会看到这种方案是怎么样实现的。    

 

轻量级指针 LightRefBase

    看罗老师的介绍,LightRefBase定义在frameworks/base/include/utils/RefBase.h文件中,但是我在看android8.0的源码时,LightRefBase的定义已经有些差别了/system/core/include/utils/LightRefBase.h

template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
            std::atomic_thread_fence(std::memory_order_acquire);
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
    inline static void renameRefId(T* /*ref*/, const void* /*old_id*/ , const void* /*new_id*/) { }

private:
    mutable std::atomic<int32_t> mCount;
};

    首先它是一个模板类,拥有一个atomic<int32_t> 类型的计数器(atomic是一个原子操作类,在c++11中新定义的。)提供了desString 和 incString的计数器增减方案,还有一个getStringCount的获取计数器数量的方法。

    这个类的实现方法可能和罗老师介绍的android2.3版本有些区别,主要集中在对于mCount的原子操作上,但是实际上这并不影响我们对于智能指针的理解和使用。

    在实现上,需要关注的是decStrong方法,如果强引用全部删除之后,我们会delete本对象!

    好了,上面我们定义了引用计数器(就是需要使用智能指针的对象都需要继承的那个公共类),它本身并没有智能指针的功能,我们需要使用一个类来控制这个引用计数,这个类就是sp类,它不仅仅是LightRefBase计数器的智能指针,同时也是强指针引用计数器的智能指针。

template<typename T>
class sp {
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);  // NOLINT(implicit)
    sp(const sp<T>& other);
    sp(sp<T>&& other);
    template<typename U> sp(U* other);  // NOLINT(implicit)
    template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
    template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)

    ~sp();

    // Assignment

    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);
    sp& operator = (sp<T>&& other);

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (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;
    void set_pointer(T* ptr);
    T* m_ptr;
};

    如果你是java用户,对c++不太熟悉的话解读代码可能有些困难,但是相信我,c/c++你值得接触。

    首先在template模板类型中,对于模板并没有类型检测,所以你会看到下面这样的代码

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);
}

    我根本不知道m_ptr的具体类型(它的类型是T,一个模板),但是我们可以直接调用 incStrong这样的方法,编译器不会帮我们检测是否合法,一切自在开发者心中。

    具体的实现代码可以自己看一下文件,无非是构造的时候调用incString,销毁的时候调用decStrong方法。至于为什么有那么多的重载,还有赋值运算符的重载,这就涉及到c++的拷贝构造等内容了。

    总之sp的功能就是模板包装LightRefBase对象,控制它的引用计数。

#include <stdio.h>
#include <utils/RefBase.h>

using namespace android;

class LightClass : public LightRefBase<LightClass>
{
public:
        LightClass()
        {
                printf("Construct LightClass Object.");
        }

        virtual ~LightClass()
        {
                printf("Destory LightClass Object.");
        }
};

int main(int argc, char** argv)
{
        LightClass* pLightClass = new LightClass();
        sp<LightClass> lpOut = pLightClass;

        printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());  //1

        {
                sp<LightClass> lpInner = lpOut;

                printf("Light Ref Count: %d.\n", pLightClass->getStrongCount()); //2
        }

        printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());//1

        return 0;
}


//print:
//Construct LightClass Object.  
//Light Ref Count: 1.  
//Light Ref Count: 2.  
//Light Ref Count: 1.  
//Destory LightClass Object.  

    例子也直接引用了罗老师的(PS:本机没有编译源代码,所以没办法自己写例子啊)。

    首先我们定义了一个最简单的类,但是需要继承与LightRefBase<T>类。

    在使用的时候我们首先创建了一个对象(创建的时候还没有开始引用计数),然后赋值给一个只能指针(引用计数开始了)。然后在局部作用域中,我们再次定义一个智能指针,并且指向了原来的对象,所以引用计数再次+1,当除了局部作用域,智能指针析构,所以引用计数-1。最终退出方法,lpout也会被析构,引用计数继续-1,这个时候引用计数为0,对象LightClass就会被delete(我们没有调用delete方法释放指针,但是它确实被自动释放了,这就是智能指针的作用)。

 

强指针

    强指针应用计数类的定义在/system/core/include/utils/RefBase.h中

class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            decStrong(const void* id) const;

            void            forceIncStrong(const void* id) const;

            //! DEBUGGING ONLY: Get current strong ref count.
            int32_t         getStrongCount() const;

    class weakref_type
    {
    public:
        RefBase*            refBase() const;

        void                incWeak(const void* id);
        void                decWeak(const void* id);

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        // acquires a weak reference if there is already one.
        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
        // for proper use.
        bool                attemptIncWeak(const void* id);

        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;

        //! DEBUGGING ONLY: Print references held on object.
        void                printRefs() const;

        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.

        void                trackMe(bool enable, bool retain);
    };

            weakref_type*   createWeak(const void* id) const;

            weakref_type*   getWeakRefs() const;

            //! DEBUGGING ONLY: Print references held on object.
    inline  void            printRefs() const { getWeakRefs()->printRefs(); }

            //! DEBUGGING ONLY: Enable tracking of object.
    inline  void            trackMe(bool enable, bool retain)
    {
        getWeakRefs()->trackMe(enable, retain);
    }

    typedef RefBase basetype;

protected:
                            RefBase();
    virtual                 ~RefBase();

    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

            void            extendObjectLifetime(int32_t mode);

    //! Flags for onIncStrongAttempted()
    enum {
        FIRST_INC_STRONG = 0x0001
    };

    // Invoked after creation of initial strong pointer/reference.
    virtual void            onFirstRef();
    // Invoked when either the last strong reference goes away, or we need to undo
    // the effect of an unnecessary onIncStrongAttempted.
    virtual void            onLastStrongRef(const void* id);
    // Only called in OBJECT_LIFETIME_WEAK case.  Returns true if OK to promote to
    // strong reference. May have side effects if it returns true.
    // The first flags argument is always FIRST_INC_STRONG.
    // TODO: Remove initial flag argument.
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
    // Invoked in the OBJECT_LIFETIME_WEAK case when the last reference of either
    // kind goes away.  Unused.
    // TODO: Remove.
    virtual void            onLastWeakRef(const void* id);

private:
    friend class weakref_type;
    class weakref_impl;

                            RefBase(const RefBase& o);
            RefBase&        operator=(const RefBase& o);

private:
    friend class ReferenceMover;

    static void renameRefs(size_t n, const ReferenceRenamer& renamer);

    static void renameRefId(weakref_type* ref,
            const void* old_id, const void* new_id);

    static void renameRefId(RefBase* ref,
            const void* old_id, const void* new_id);

        weakref_impl* const mRefs;
};

    同样定义了 incStrong 和decStrong方法,用于增减引用计数(这也是为什么强指针也能使用sp<T>类来控制引用计数的原因)。和轻量级指针引用计数不同的是,我们的引用计数量不再是一个int类型(轻量级中使用std::atomic<int32_t>)来记录引用数量,而是使用了一个weakref_impl指针类型的变量mRefs。

    weakref_impl是继承与上面weakref_type的一个类,定义在/system/core/libutils/RefBase.cpp文件中。

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;

#if !DEBUG_REFS

    explicit weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }

    void addStrongRef(const void* /*id*/) { }
    void removeStrongRef(const void* /*id*/) { }
    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void addWeakRef(const void* /*id*/) { }
    void removeWeakRef(const void* /*id*/) { }
    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
    void printRefs() const { }
    void trackMe(bool, bool) { }

#else
......
#endif

    我们只关注这一段,下面省略的部分是用于debug的,这里直接略过了。在release版本上,这些函数都是空实现,所以实际有用的就是最上面定义的4个成员变量。mStrong 和 mWeak分别用来做强引用和弱引用的计数,mBase指向实现引用计数的对象本身,mFlags是标志位,默认值是0,作用后面一点点看。

    我们会以sp<T>的构造函数,关于增减引用计数,使用的方法是incStrong和decStrong。所以RefBase中一定也是通过这两个方法真正来实现关于引用计数的增减的,我们先来看一下incStrong(RefBase.cpp中)

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);

    refs->addStrongRef(id);
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    if (c != INITIAL_STRONG_VALUE)  {
        return;
    }

    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
    // A decStrong() must still happen after us.
    ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
    refs->mBase->onFirstRef();
}

    这里把构造函数也列出来,我们可以知道,mRefs的对象就是wekref_impl。

    incStrong首先调用incWeak看函数名是用来增加弱引用计数的

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

    弱引用简单+1,没有其他操作。

    然后调用addStrongRef,在release版本中是个空实现,所以这里也就不介绍了。

    关键是下面 fetch_add 在强引用计数上+1(返回值是原来的值)。如果是初始值(INITIAL_STRONG_VALUE),表示是第一次被强引用,那么久调用fetch_sub,将mStrong归1(初始值不为0,是1<<28,所以上面+1之后是 1<<28+1,这里减去初始值之后才会变成1。相比使用boolean标记为,这样的方式似乎也挺优雅的,值得学习),并且还会调用onFirstRef来做第一次被引用的处理(开发者自己定义,RefBase类中是个空实现)。

    然后是decStrong 

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That''s OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it''s deleting
    // mRefs itself, or it''s running entirely before the final mWeak decrement.
    refs->decWeak(id);
}

    removeStrongRef也是空实现。

    使用fetch_sub对强引用计数器-1,如果当前没有其他强引用了,那么调用onLastStrongRef方法(和之前的onFirstRef对应)。

    在继续解读之前需要了解一个enum

//! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

    这个枚举量是用来控制对象生命周期的,如果设置为OBJECT_LIFETIME_STRONG表示,对象如果强引用计数器为0,就表示生命周期终止,需要delete,如果设置为OBJECT_LIFETIME_WEAK,表示,只有当弱引用和强引用计数器都为0时,才会delete对象。

    所以回到上面代码,decStrong会判断对象的生命周期类型,如果是OBJECT_LIFETIME_STRONG,那么我们会直接delete自己。delete会调用析构函数


RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    // Life-time of this object is extended to WEAK, in
    // which case weakref_impl doesn''t out-live the object and we
    // can free it now.
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
        // It''s possible that the weak count is not 0 if the object
        // re-acquired a weak reference in its destructor
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {
        // We never acquired a strong reference on this object.
        LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
                "RefBase: Explicit destruction with non-zero weak "
                "reference count");
        // TODO: Always report if we get here. Currently MediaMetadataRetriever
        // C++ objects are inconsistently managed and sometimes get here.
        // There may be other cases, but we believe they should all be fixed.
        delete mRefs;
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp''s.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

    析构函数中做了一件很重要的事情,释放mRefs计数对象(我们在构造函数的时候new的,所以需要确保释放)。但是并不是直接mRefs就可以的,如果当前对象生命周期是受弱引用控制的,那么只有在弱引用计数为0的时候,才会去销毁mRefs(其实如果调用了析构函数,并且是弱引用控制的,那么理论上弱引用计数应该就是0)。如果生命周期受到强引用控制,那么只有在该对象从来没有申请过强引用的情况下才会释放mRefs,如果申请过强引用,这种情况该对象的释放会在decWeak方法中执行(析构时可能弱引用计数还不为0,这个时候这个计数对象是不应该销毁的)。

    回到decStrong,最后,不论生命周期如何,还需要调用decWeak将弱引用-1。

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    if (c != 1) return;
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlives the object, it is not destroyed in the dtor, and
        // we''ll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Decrementing a weak count to zero when object never had a strong
            // reference.  We assume it acquired a weak reference early, e.g.
            // in the constructor, and will eventually be properly destroyed,
            // usually via incrementing and decrementing the strong count.
            // Thus we no longer do anything here.  We log this case, since it
            // seems to be extremely rare, and should not normally occur. We
            // used to deallocate mBase here, so this may now indicate a leak.
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

    如果你看过罗老师的智能指针,你回发现,这个方法已经有所不同了。removeWeakRef这些在release中空实现略过。通过fetch_sub在弱引用计数上-1,然后判断是否为最后一个弱引用,如果不是,直接返回。接下去的地方逻辑有些绕,先来看第一个else部分:

    如果对象生命周期受到弱引用控制,那么当弱引用为0时,delete impl->mBase(相当于delete this!)。

    如果受到强引用控制,那么分成两种情况,是否存在或者曾经存在强引用,如果从没有存在过强引用,并且这个时候弱引用为0了,这种情况一般不会出现,所以什么也不做,就打印。如果存在过强引用,那么对象的生命周期是强引用控制的,理论上在强引用为0的时候会被释放,不需要你来负责释放对象,只需要负责释放mRef对象(这个对象的生命周期并不是和对象本身绑定的,对象地址会被wp<T>持有,即使本对象delete了,mRef还是存在,并且调用decWeak完全没问题,这种情况下就不能再析构函数中直接释放mRef对象,而是需要在弱引用计数为0之后主动释放对象)。

    强指针的类就是sp<T>这个前面已经说过了,这里就不介绍了。

弱指针

    弱指针使用的引用计数类同样是RefBase类,这是不出所料的,因为在分析强指针的时候已经看到了一些关于弱指针的引用计数情况。

    弱指针的实现类是wp<T>,位于/system/core/inlucde/utils/RefBase.h文件中,和RefBase类定义在同一个头文件中。

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    wp(T* other);  // NOLINT(implicit)
    wp(const wp<T>& other);
    explicit wp(const sp<T>& other);
    template<typename U> wp(U* other);  // NOLINT(implicit)
    template<typename U> wp(const sp<U>& other);  // NOLINT(implicit)
    template<typename U> wp(const wp<U>& other);  // NOLINT(implicit)

    ~wp();

    // Assignment

    wp& operator = (T* other);
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& other);

    template<typename U> wp& operator = (U* other);
    template<typename U> wp& operator = (const wp<U>& other);
    template<typename U> wp& operator = (const sp<U>& other);

    void set_object_and_refs(T* other, weakref_type* refs);

    // promotion to sp

    sp<T> promote() const;

    // Reset

    void clear();

    // Accessors

    inline  weakref_type* get_refs() const { return m_refs; }

    inline  T* unsafe_get() const { return m_ptr; }

    // Operators

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

    inline bool operator == (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
    }
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_ptr == o.m_ptr;
    }

    inline bool operator > (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }
    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
    }

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
    template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};

        wp<T>类的定义和sp<T>其实是比较接近的,最大的区别在于wp<T> 不仅保存了 T的指针 m_ptr,而且保存了T中引用计数的指针m_refs。

    首先,在最基本型的构造函数中,会调用createWeak方法,并且将返回值存入m_refs中

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}



RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}

    而createWeak方法(定义在RefBase.cpp中)一并列在了上面,调用incWeak增加弱引用计数,并且返回mRefs对象指针。

    sp的析构函数会调用decStrong,相应的,wp的析构函数应该会调用decWeak。但是不同的地方在于,sp只世界调用对象T*的方法,而decWeak方法定义在weakref_type对象上。

    关于decWeak的实现在上面章节已经介绍过了。

    分析到这里,弱指针还没介绍完,它最重要的特性我们还没有分析到。前面我们说过,弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了:

template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}

    其中attemptIncStrong算是智能指针中比较长的一个函数,我们分段来看

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);
    .......
}

    首先,不管三七二十一,先增加弱引用计数一次(增加强引用计数的时候弱引用计数也需要+1,上面incStrong也有这个操作。)

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    ........

    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);

    ALOG_ASSERT(curCount >= 0,
            "attemptIncStrong called on %p after underflow", this);

    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        // we''re in the easy/common case of promoting a weak-reference
        // from an existing strong reference.
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation. curCount was updated by compare_exchange_weak.
    }
    .........
}

    然后获取当前强引用计数器的值,如果当前已经有其他强引用,那么表示对象一定存在,所以这里就试着将强引用引用计数+1。

    有两个疑问点,while循环和 compare_exchange_weak方法,其实都是考虑到多线程的时候同时操作出现的问题。具体不分析了,需要研究atomic的方法。

 

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    ..........

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we''re now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            ........
        } else {
            // this object has an "extended" life-time, i.e.: it can be
            // revived from a weak-reference only.
            // Ask the object''s implementation if it agrees to be revived
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                // it didn''t so give-up.
                decWeak(id);
                return false;
            }
            // grab a strong-reference, which is always safe due to the
            // extended life-time.
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            // If the strong reference count has already been incremented by
            // someone else, the implementor of onIncStrongAttempted() is holding
            // an unneeded reference.  So call onLastStrongRef() here to remove it.
            // (No, this is not pretty.)  Note that we MUST NOT do this if we
            // are in fact acquiring the first reference.
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                impl->mBase->onLastStrongRef(id);
            }
        }
    }

    .......
}

    如果当前没有强引用的,那么就会分成两种情况,就是对象生命周期受谁的控制。

    我们先看对象生命周期受弱引用控制,而现在我们正通过弱引用尝试升级到强引用,这就说明弱引用肯定不为0,那么对象一定是存在的。不过我们在RefBase中还是添加了一个方法,onIncStrongAttempted用来询问是否允许升级到强指针,默认返回true表示允许,但是部分对象可能不允许做弱引用升级(重写该方法,返回false即可),如果不允许,那么久弱引用-1(回退第一步操作),直接然后返回false。如果允许弱引用升级,那么就强引用+1。

 

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    ...........

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        // we''re now in the harder case of either:
        // - there never was a strong reference on us
        // - or, all strong references have been released
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            // this object has a "normal" life-time, i.e.: it gets destroyed
            // when the last strong reference goes away
            if (curCount <= 0) {
                // the last strong-reference got released, the object cannot
                // be revived.
                decWeak(id);
                return false;
            }

            // here, curCount == INITIAL_STRONG_VALUE, which means
            // there never was a strong-reference, so we can try to
            // promote this object; we need to do that atomically.
            while (curCount > 0) {
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
                // the strong count has changed on us, we need to re-assert our
                // situation (e.g.: another thread has inc/decStrong''ed us)
                // curCount has been updated.
            }

            if (curCount <= 0) {
                // promote() failed, some other thread destroyed us in the
                // meantime (i.e.: strong count reached zero).
                decWeak(id);
                return false;
            }
        } else {
            ..........
        }
    }

    ......
}

        如果对象的生命周期受强引用控制,那么又会分成两个情况,当前的强引用计数是否为初始值,如果不是初始值,那么表示曾经有过强引用,并且现在没有了,这种情况下,对象已经被delete掉了,所以需要弱引用-1作回退,然后返回false。如果强引用计数等于初始值,表示对象还没有强引用,自然也没有被销毁,可以转换,所以强引用+1。这里有个问题,+1之后的值并不是  1,而是 1<<28,所以才有下面最后这段代码

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    .....

    impl->addStrongRef(id);

#if PRINT_REFS
    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif

    // curCount is the value of mStrong before we incremented it.
    // Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
    // This must be done safely, i.e.: handle the case where several threads
    // were here in attemptIncStrong().
    // curCount > INITIAL_STRONG_VALUE is OK, and can happen if we''re doing
    // this in the middle of another incStrong.  The subtraction is handled
    // by the thread that started with INITIAL_STRONG_VALUE.
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}

    addStringRef是空实现,不管,关键是下面,如果之前没有过强引用,这里需要在强引用计数上减去1<<28。

    至此,弱指针的分析也结束了。

强弱指针应用

    说了那么多,如果不需要了解实现逻辑,用例子来说明是最直接的,下面还是直接引用了罗老师的例子(有所调整,去掉了ForeverClass,因为在android8.0中已经没有Forever的标志了)

#include <stdio.h>
#include <utils/RefBase.h>

#define INITIAL_STRONG_VALUE (1<<28)

using namespace android;

class WeightClass : public RefBase
{
public:
        void printRefCount()
        {
                int32_t strong = getStrongCount();
                weakref_type* ref = getWeakRefs();

                printf("-----------------------\n");
                printf("Strong Ref Count: %d.\n", (strong  == INITIAL_STRONG_VALUE ? 0 : strong));
                printf("Weak Ref Count: %d.\n", ref->getWeakCount());
                printf("-----------------------\n");
        }
};

class StrongClass : public WeightClass
{
public:
        StrongClass()
        {
                printf("Construct StrongClass Object.\n");
        }

        virtual ~StrongClass()
        {
                printf("Destory StrongClass Object.\n");
        }
};


class WeakClass : public WeightClass
{
public:
        WeakClass()
        {
                extendObjectLifetime(OBJECT_LIFETIME_WEAK);

                printf("Construct WeakClass Object.\n");
        }

        virtual ~WeakClass()
        {
                printf("Destory WeakClass Object.\n");
        }
};


void TestStrongClass(StrongClass* pStrongClass)
{
        wp<StrongClass> wpOut = pStrongClass;
        pStrongClass->printRefCount();

        {
                sp<StrongClass> spInner = pStrongClass;
                pStrongClass->printRefCount();
        }

        sp<StrongClass> spOut = wpOut.promote();
        printf("spOut: %p.\n", spOut.get());
}

void TestWeakClass(WeakClass* pWeakClass)
{
        wp<WeakClass> wpOut = pWeakClass;
        pWeakClass->printRefCount();

        {
                sp<WeakClass> spInner = pWeakClass;
                pWeakClass->printRefCount();
        }

        pWeakClass->printRefCount();
        sp<WeakClass> spOut = wpOut.promote();
        printf("spOut: %p.\n", spOut.get());
}


int main(int argc, char** argv)
{
        printf("Test Strong Class: \n");
        StrongClass* pStrongClass = new StrongClass();
        TestStrongClass(pStrongClass);


//Test Strong Class:   
//Construct StrongClass Object.  
//-----------------------  
//Strong Ref Count: 0.  
//Weak Ref Count: 1.  
//-----------------------  
//-----------------------  
//Strong Ref Count: 1.  
//Weak Ref Count: 2.  
//-----------------------  
//Destory StrongClass Object.  
//spOut: 0x0. 


        printf("\nTest Weak Class: \n");
        WeakClass* pWeakClass = new WeakClass();
        TestWeakClass(pWeakClass);

//Test Weak Class:   
//Construct WeakClass Object.  
//-----------------------  
//Strong Ref Count: 0.  
//Weak Ref Count: 1.  
//-----------------------  
//-----------------------  
//Strong Ref Count: 1.  
//Weak Ref Count: 2.  
//-----------------------  
//-----------------------  
//Strong Ref Count: 0.  
//Weak Ref Count: 1.  
//-----------------------  
//spOut: 0xa528.  
//Destory WeakClass Object.

        return 0;
}

    WeightClass是基类,主要用于输出当前引用计数的数量。定义了WeakClass 和StringClass 让他们的生命周期分别受控于弱引用计数和强引用计数。

    TestStringClass中,首先创建了一个弱指针,所以输出弱引用计数+1,强引用计数不变。然后在局部作用域中创建了一个强指针,很明显强引用和弱引用都会+1,当退出局部作用域,强指针自动释放,所以强弱指针都会-1,这个时候强指针计数变成了0,那么对象就会被自动delete,会输出析构函数中的打赢,所以当我们尝试将弱指针提升为强指针,应该会返回false,升级失败,所以最后输出一个空地址。最后退出,最后一个弱引用自动销毁,所以弱引用计数变为0,引用计数器类(weakref_impl)会被释放,不会出现内存泄漏。

    TestWeakClass中,操作几乎和TestStringClass相同,不同点发生在退出局部作用域,这个时候虽然强引用变为0,但是弱引用并不是0,由于对象生命周期受弱引用计数控制,所以对象不会被销毁,当我们尝试升级弱引用的时候自然能够成功。当退出函数,弱引用和强引用都自动被释放,这个时候对象才会被销毁。

 

参考

http://blog.csdn.net/luoshengyang/article/details/6786239

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析

Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针、强指针和弱指针)的实现原理。

在使用C++来编写代码的过程中,指针使用不当造成内存泄漏一般就是因为new了一个对象并且使用完之后,忘记了delete这个对象,而造成系统崩溃一般就是因为一个地方delete了这个对象之后,其它地方还在继续使原来指向这个对象的指针。

为了避免出现上述问题,一般的做法就是使用引用计数的方法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还在使用的问题了。

但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,要开发人员时刻记住什么时候该对这个对象的引用计数加1,什么时候该对这个对象的引用计数减1,一来是不方便开发,二来是不可靠,一不小心哪里多加了一个1或者多减了一个1,就会造成灾难性的后果。这时候,智能指针就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。

在计算机科学领域中,提供垃圾收集(Garbage Collection)功能的系统框架,即提供对象托管功能的系统框架,例如Java应用程序框架,也是采用上述的引用计数技术方案来实现的,然而,简单的引用计数技术不能处理系统中对象间循环引用的情况。考虑这样的一个场景,系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏。这样,就要采取另外的一种引用计数技术了,即对象的引用计数同时存在强引用和弱引用两种计数,例如,Apple公司提出的Cocoa框架,当父对象要引用子对象时,就对子对象使用强引用计数技术,而当子对象要引用父对象时,就对父对象使用弱引用计数技术,而当垃圾收集系统执行对象回收工作时,只要发现对象的强引用计数为0,而不管它的弱引用计数是否为0,都可以回收这个对象,但是,如果我们只对一个对象持有弱引用计数,当我们要使用这个对象时,就不直接使用了,必须要把这个弱引用升级成为强引用时,才能使用这个对象,在转换的过程中,如果对象已经不存在,那么转换就失败了,这时候就说明这个对象已经被销毁了,不能再使用了。

了解了这些背景知识后,我们就可以进一步学习Android系统的智能指针的实现原理了。Android系统提供了强大的智能指针技术供我们使用,这些智能指针实现方案既包括简单的引用计数技术,也包括了复杂的引用计数技术,即对象既有强引用计数,也有弱引用计数,对应地,这三种智能指针分别就称为轻量级指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Weak Pointer)。无论是轻量级指针,还是强指针和弱指针,它们的实现框架都是一致的,即由对象本身来提供引用计数器,但是它不会去维护这个引用计数器的值,而是由智能指针来维护,就好比是对象提供素材,但是具体怎么去使用这些素材,就交给智能指针来处理了。由于不管是什么类型的对象,它都需要提供引用计数器这个素材,在C++中,我们就可以把这个引用计数器素材定义为一个公共类,这个类只有一个成员变量,那就是引用计数成员变量,其它提供智能指针引用的对象,都必须从这个公共类继承下来,这样,这些不同的对象就天然地提供了引用计数器给智能指针使用了。总的来说就是我们在实现智能指会的过程中,第一是要定义一个负责提供引用计数器的公共类,第二是我们要实现相应的智能指针对象类,后面我们会看到这种方案是怎么样实现的。

接下来,我们就先介绍轻量级指针的实现原理,然后再接着介绍强指针和弱指针的实现原理。

1. 轻量级指针

先来看一下实现引用计数的类LightRefBase,它定义在frameworks/base/include/utils/RefBase.h文件中:

template <class T>
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);
		}
	}
	//! DEBUGGING ONLY: Get current strong ref count.
	inline int32_t getStrongCount() const {
		return mCount;
	}
 
protected:
	inline ~LightRefBase() { }
 
private:
	mutable volatile int32_t mCount;
};

这个类很简单,它只一个成员变量mCount,这就是引用计数器了,它的初始化值为0,另外,这个类还提供两个成员函数incStrong和decStrong来维护引用计数器的值,这两个函数就是提供给智能指针来调用的了,这里要注意的是,在decStrong函数中,如果当前引用计数值为1,那么当减1后就会变成0,于是就会delete这个对象。

前面说过,要实现自动引用计数,除了要有提供引用计数器的基类外,还需要有智能指针类。在Android系统中,配合LightRefBase引用计数使用的智能指针类便是sp了,它也是定义在frameworks/base/include/utils/RefBase.h文件中:

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;
};

这个类的内容比较多,但是这里我们只关注它的成员变量m_ptr、构造函数和析构函数。不难看出,成员变量m_ptr就是指向真正的对象了,它是在构造函数里面初始化的。接下来我们就再看一下它的两个构造函数,一个是普通构造函数,一个拷贝构造函数:

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);
}

这两个构造函数都会首先初始化成员变量m_ptr,然后再调用m_ptr的incStrong函数来增加对象的引用计数,在我们这个场景中,就是调用LightRefBase类的incStrong函数了。

最后,看一下析构函数:

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

析构函数也很简单,只是调用m_ptr的成员函数decStrong来减少对象的引用计数值,这里就是调用LightRefBase类的decStrong函数了,前面我们看到,当这个引用计数减1后变成0时,就会自动delete这个对象了。

轻量级智能指针的实现原理大概就是这样了,比较简单,下面我们再用一个例子来说明它的用法。

2. 轻量级指针的用法

我们在external目录下建立一个C++工程目录lightpointer,它里面有两个文件,一个lightpointer.cpp文件,另外一个是Android.mk文件。

源文件lightpointer.cpp的内容如下:

#include <stdio.h>
#include <utils/RefBase.h>
 
using namespace android;
 
class LightClass : public LightRefBase<LightClass>
{
public:
        LightClass()
        {
                printf("Construct LightClass Object.");
        }
 
        virtual ~LightClass()
        {
                printf("Destory LightClass Object.");
        }
};
 
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;
}

我们创建一个自己的类LightClass,继承了LightRefBase模板类,这样类LightClass就具有引用计数的功能了。在main函数里面,我们首先new一个LightClass对象,然后把这个对象赋值给智能指针lpOut,这时候通过一个printf语句来将当前对象的引用计数值打印出来,从前面的分析可以看出,如果一切正常的话,这里打印出来的引用计数值为1。接着,我们又在两个大括号里面定义了另外一个智能指针lpInner,它通过lpOut间接地指向了前面我们所创建的对象,这时候再次将当前对象的引用计数值打印出来,从前面的分析也可以看出,如果一切正常的话,这里打印出来的引用计数值应该为2。程序继承往下执行,当出了大括号的范围的时候,智能指针对象lpInner就被析构了,从前面的分析可以知道,智能指针在析构的时候,会减少当前对象的引用计数值,因此,最后一个printf语句打印出来的引用计数器值应该为1。当main函数执行完毕后,智能指针lpOut也会被析构,被析构时,它会再次减少当前对象的引用计数,这时候,对象的引用计数值就为0了,于是,它就会被delete了。

编译脚本文件Android.mk的内容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := lightpointer
LOCAL_SRC_FILES := lightpointer.cpp
LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libutils
include $(BUILD_EXECUTABLE)

最后,我们参照如何单独编译Android源代码中的模块一文,使用mmm命令对工程进行编译:

USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer

编译之后,就可以打包了:

USER-NAME@MACHINE-NAME:~/Android$ make snod

最后得到可执行程序lightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行lightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:

USER-NAME@MACHINE-NAME:~/Android$ adb shell
root@android:/ # cd system/bin/        
root@android:/system/bin # ./lightpointer                                      
Construct LightClass Object.
Light Ref Count: 1.
Light Ref Count: 2.
Light Ref Count: 1.
Destory LightClass Object.

这里可以看出,程序一切都是按照我们的设计来运行,这也验证了我们上面分析的轻量级智能指针的实现原理。

3. 强指针

强指针所使用的引用计数类为RefBase,它LightRefBase类要复杂多了,所以才称后者为轻量级的引用计数基类吧。我们先来看看RefBase类的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:

class RefBase
{
public:
	void            incStrong(const void* id) const;
	void            decStrong(const void* id) const;
 
	void            forceIncStrong(const void* id) const;
 
	//! DEBUGGING ONLY: Get current strong ref count.
	int32_t         getStrongCount() const;
 
	class weakref_type
	{
	public:
		RefBase*            refBase() const;
 
		void                incWeak(const void* id);
		void                decWeak(const void* id);
 
		bool                attemptIncStrong(const void* id);
 
		//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
		bool                attemptIncWeak(const void* id);
 
		//! DEBUGGING ONLY: Get current weak ref count.
		int32_t             getWeakCount() const;
 
		//! DEBUGGING ONLY: Print references held on object.
		void                printRefs() const;
 
		//! DEBUGGING ONLY: Enable tracking for this object.
		// enable -- enable/disable tracking
		// retain -- when tracking is enable,if true,then we save a stack trace
		//           for each reference and dereference; when retain == false,we
		//           match up references and dereferences and keep only the 
		//           outstanding ones.
 
		void                trackMe(bool enable,bool retain);
	};
 
	weakref_type*   createWeak(const void* id) const;
 
	weakref_type*   getWeakRefs() const;
 
	//! DEBUGGING ONLY: Print references held on object.
	inline  void            printRefs() const { getWeakRefs()->printRefs(); }
 
	//! DEBUGGING ONLY: Enable tracking of object.
	inline  void            trackMe(bool enable,bool retain)
	{
		getWeakRefs()->trackMe(enable,retain);
	}
 
protected:
	RefBase();
	virtual                 ~RefBase();
 
	//! Flags for extendobjectLifetime()
	enum {
		OBJECT_LIFETIME_WEAK    = 0x0001,OBJECT_LIFETIME_FOREVER = 0x0003
	};
 
	void            extendobjectLifetime(int32_t mode);
 
	//! Flags for onIncStrongAttempted()
	enum {
		FirsT_INC_STRONG = 0x0001
	};
 
	virtual void            onFirstRef();
	virtual void            onLastStrongRef(const void* id);
	virtual bool            onIncStrongAttempted(uint32_t flags,const void* id);
	virtual void            onLastWeakRef(const void* id);
 
private:
	friend class weakref_type;
	class weakref_impl;
 
	RefBase(const RefBase& o);
	RefBase&        operator=(const RefBase& o);
 
	weakref_impl* const mRefs;
};

RefBase类和LightRefBase类一样,提供了incStrong和decStrong成员函数来操作它的引用计数器;而RefBase类与LightRefBase类最大的区别是,它不像LightRefBase类一样直接提供一个整型值(mutable volatile int32_t mCount)来维护对象的引用计数,前面我们说过,复杂的引用计数技术同时支持强引用计数和弱引用计数,在RefBase类中,这两种计数功能是通过其成员变量mRefs来提供的。

RefBase类的成员变量mRefs的类型为weakref_impl指针,它实现在frameworks/base/libs/utils/RefBase.cpp文件中:

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
	volatile int32_t    mStrong;
	volatile int32_t    mWeak;
	RefBase* const      mBase;
	volatile int32_t    mFlags;
 
 
#if !DEBUG_REFS
 
	weakref_impl(RefBase* base)
		: mStrong(INITIAL_STRONG_VALUE),mWeak(0),mBase(base),mFlags(0)
	{
	}
 
	void addStrongRef(const void* /*id*/) { }
	void removeStrongRef(const void* /*id*/) { }
	void addWeakRef(const void* /*id*/) { }
	void removeWeakRef(const void* /*id*/) { }
	void printRefs() const { }
	void trackMe(bool,bool) { }
 
#else
	weakref_impl(RefBase* base)
		: mStrong(INITIAL_STRONG_VALUE),mFlags(0),mStrongRefs(NULL),mWeakRefs(NULL),mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT),mRetain(false)
	{
		//LOGI("NEW weakref_impl %p for RefBase %p",this,base);
	}
 
	~weakref_impl()
	{
		LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL,"Strong references remain!");
		LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL,"Weak references remain!");
	}
 
	void addStrongRef(const void* id)
	{
		addRef(&mStrongRefs,id,mStrong);
	}
 
	void removeStrongRef(const void* id)
	{
		if (!mRetain)
			removeRef(&mStrongRefs,id);
		else
			addRef(&mStrongRefs,-mStrong);
	}
 
	void addWeakRef(const void* id)
	{
		addRef(&mWeakRefs,mWeak);
	}
	void removeWeakRef(const void* id)
	{
		if (!mRetain)
			removeRef(&mWeakRefs,id);
		else
			addRef(&mWeakRefs,-mWeak);
	}
 
	void trackMe(bool track,bool retain)
	{
		mTrackEnabled = track;
		mRetain = retain;
	}
 
	......
 
private:
	struct ref_entry
	{
		ref_entry* next;
		const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
		CallStack stack;
#endif
		int32_t ref;
	};
 
	void addRef(ref_entry** refs,const void* id,int32_t mRef)
	{
		if (mTrackEnabled) {
			AutoMutex _l(mMutex);
			ref_entry* ref = new ref_entry;
			// Reference count at the time of the snapshot,but before the
			// update.  Positive value means we increment,negative--we
			// decrement the reference count.
			ref->ref = mRef;
			ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
			ref->stack.update(2);
#endif
 
			ref->next = *refs;
			*refs = ref;
		}
	}
 
	void removeRef(ref_entry** refs,const void* id)
	{
		if (mTrackEnabled) {
			AutoMutex _l(mMutex);
 
			ref_entry* ref = *refs;
			while (ref != NULL) {
				if (ref->id == id) {
					*refs = ref->next;
					delete ref;
					return;
				}
 
				refs = &ref->next;
				ref = *refs;
			}
 
			LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",mBase,this);
		}
	}
 
	......
 
	Mutex mMutex;
	ref_entry* mStrongRefs;
	ref_entry* mWeakRefs;
 
	bool mTrackEnabled;
	// Collect stack traces on addref and removeref,instead of deleting the stack references
	// on removeref that match the address ones.
	bool mRetain;
 
	......
#endif
};

这个类看起来实现得很复杂,其实不然,这个类的实现可以分成两部分:

#if !DEBUG_REFS
 
......
 
#else

编译指令之间的这部分源代码是Release版本的源代码,它的成员函数都是空实现;

#else 
 
......
 
#endif

编译指令之间的部分源代码是Debug版本的源代码,它的成员函数都是有实现的,实现这些函数的目的都是为了方便开发人员调试引用计数用的,除此之外,还在内部实现了一个结构体ref_entry:

struct ref_entry
{
	ref_entry* next;
	const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
	CallStack stack;
#endif
	int32_t ref;
};

这个结构体也是为了方便调试而使用的,我们可以不关注这部分用于调试的代码。

总的来说,weakref_impl类只要提供了以下四个成员变量来维护对象的引用计数:

volatile int32_t    mStrong;
volatile int32_t    mWeak;
RefBase* const      mBase;
volatile int32_t    mFlags;

其中mStrong和mWeak分别表示对象的强引用计数和弱引用计数;RefBase类包含了一个weakref_impl类指针mRefs,而这里的weakref_impl类也有一个成员变量mBase来指向它的宿主类RefBase;mFlags是一个标志位,它指示了维护对象引用计数所使用的策略,后面我们将会分析到,它的取值为0,或者以下的枚举值:

//! Flags for extendobjectLifetime()
enum {
    OBJECT_LIFETIME_WEAK    = 0x0001,OBJECT_LIFETIME_FOREVER = 0x0003
};

这里我们还需要注意的一点的是,从weakref_impl的类名来看,它应该是一个实现类,那么,就必然有一个对应的接口类,这个对应的接口类的就是RefBase类内部定义的weakref_type类了,这是一种把类的实现与接口定义分离的设计方法。学习过设计模式的读者应该知道,在设计模式里面,非常强调类的接口定义和类的实现分离,以便利于后续扩展和维护,这里就是用到了这种设计思想。

说了这多,RefBase类给人的感觉还是挺复杂的,不要紧,我们一步步来,先通过下面这个图来梳理一下这些类之间的关系:

从这个类图可以看出,每一个RefBase对象包含了一个weakref_impl对象,而weakref_impl对象实现了weakref_type接口,同时它可以包含多个ref_entry对象,前面说过,ref_entry是调试用的一个结构体,实际使用中可以不关注。

提供引用计数器的类RefBase我们就暂时介绍到这里,后面我们再结合智能指针类一起分析,现在先来看看强指针类和弱指针类的定义。强指针类的定义我们在前面介绍轻量级指针的时候已经见到了,就是sp类了,这里就不再把它的代码列出来了。我们来看看它的构造函数的实现:

template<typename T>
sp<T>::sp(T* other)
    : m_ptr(other)
{
    if (other) other->incStrong(this);
}

这里传进来的参数other一定是继承于RefBase类的,因此,在函数的内部,它调用的是RefBase类的incStrong函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->addWeakRef(id);
    refs->incWeak(id);
    refs->addStrongRef(id); 
 
    const int32_t c = android_atomic_inc(&refs->mStrong); 
    LOG_ASSERT(c > 0,"incStrong() called on %p after last strong ref",refs);
 
    #if PRINT_REFS 
    LOGD("incStrong of %p from %p: cnt=%d\n",c);
    #endif 
 
    if (c != INITIAL_STRONG_VALUE) { 
        return; 
    } 
 
    android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong); 
    const_cast<RefBase*>(this)->onFirstRef();
}

成员变量mRefs是在RefBase类的构造函数中创建的:

在这个incStrong函数中,主要做了三件事情:

一是增加弱引用计数:

refs->addWeakRef(id);
refs->incWeak(id);

二是增加强引用计数:

refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong);

三是如果发现是首次调用这个对象的incStrong函数,就会调用一个这个对象的onFirstRef函数,让对象有机会在对象被首次引用时做一些处理逻辑:

if (c != INITIAL_STRONG_VALUE)  {
    return;
}
 
android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong);
const_cast<RefBase*>(this)->onFirstRef();

这里的c返回的是refs->mStrong加1前的值,如果发现等于INITIAL_STRONG_VALUE,就说明这个对象的强引用计数是第一次被增加,因此,refs->mStrong就是初始化为INITIAL_STRONG_VALUE的,它的值为:

#define INITIAL_STRONG_VALUE (1<<28)

这个值加1后等于1<<28 + 1,不等于1,因此,后面要再减去-INITIAL_STRONG_VALUE,于是,refs->mStrong就等于1了,就表示当前对象的强引用计数值为1了,这与这个对象是第一次被增加强引用计数值的逻辑是一致的。

回过头来看弱引用计数是如何增加的,首先是调用weakref_impl类的addWeakRef函数,我们知道,在Release版本中,这个函数也不做,而在Debug版本中,这个函数增加了一个ref_entry对象到了weakref_impl对象的mWeakRefs列表中,表示此weakref_impl对象的弱引用计数被增加了一次。接着又调用了weakref_impl类的incWeak函数,真正增加弱引用计数值就是在这个函数实现的了,weakref_impl类的incWeak函数继承于其父类weakref_type的incWeak函数:

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id);
    const int32_t c = android_atomic_inc(&impl->mWeak);
    LOG_ASSERT(c >= 0,"incWeak called on %p after last weak ref",this);
}

增加弱引用计数是下面语句执行的:

const int32_t c = android_atomic_inc(&impl->mWeak);

但是前面为什么又调用了一次addWeakRef函数呢?前面不是已经调用过了吗?在Release版本中,因为weakref_impl类的addWeakRef函数是空实现,这里再调用一次没有什么害处,但是如果在Debug版本,岂不是冗余了吗?搞不清,有人问过负责开发Android系统Binder通信机制模块的作者Dianne Hackborn这个问题,他是这样回答的:

Ah I see. Well the debug code may be broken,though I wouldn't leap to that
conclusion without actually testing it; I kNow it has been used in the
past. Anyway,these things get compiled out in non-debug builds,so there
is no reason to change them unless you are actually trying to use this debug
code and it isn't working and need to do this to fix it.

既然他也不知道怎么回事,我们也不必深究了,知道有这么回事就行。

这里总结一下强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。

再来看看强指针类的析构函数的实现:

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

同样,这里的m_ptr指向的目标对象一定是继承了RefBase类的,因此,这里调用的是RefBase类的decStrong函数,这也是定义在frameworks/base/libs/utils/RefBase.cpp文件中:

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
    LOGD("decStrong of %p from %p: cnt=%d\n",c);
#endif
    LOG_ASSERT(c >= 1,"decStrong() called on %p too many times",refs);
    if (c == 1) {
        const_cast<RefBase*>(this)->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
            delete this;
        }
    }
    refs->removeWeakRef(id);
    refs->decWeak(id);
}

这里的refs->removeStrongRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addStrongRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作是下面语句:

const int32_t c = android_atomic_dec(&refs->mStrong);

如果发现减1前,此对象的强引用计数为1,就说明从此以后,就再没有地方引用这个目标对象了,这时候,就要看看是否要delete这个目标对象了:

if (c == 1) {
    const_cast<RefBase*>(this)->onLastStrongRef(id);
    if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
        delete this;
    }
}

在强引用计数为0的情况下,如果对象的标志位OBJECT_LIFETIME_WEAK被设置了,就说明这个对象的生命周期是受弱引用计数所控制的,因此,这时候就不能delete对象,要等到弱引用计数也为0的情况下,才能delete这个对象。

接下来的ref->removeWeakRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addWeakRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作下面的refs->decWeak函数,weakref_impl类没有实现自己的decWeak函数,它继承了weakref_type类的decWeak函数:

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = android_atomic_dec(&impl->mWeak);
    LOG_ASSERT(c >= 1,"decWeak called on %p too many times",this);
    if (c != 1) return;
 
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
        if (impl->mStrong == INITIAL_STRONG_VALUE)
            delete impl->mBase;
        else {
//            LOGV("Freeing refs %p of old RefBase %p\n",impl->mBase);
            delete impl;
        }
    } else {
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
            delete impl->mBase;
        }
    }
}

这里又一次调用了weakref_impl对象的removeWeakRef函数,这也是和RefBase::weakref_type::incWeak函数里面的impl->addWeakRef语句所对应的,实现弱引用计数减1的操作是下面语句:

const int32_t c = android_atomic_dec(&impl->mWeak);

减1前如果发现不等于1,那么就什么也不用做就返回了,如果发现等于1,就说明当前对象的弱引用计数值为0了,这时候,就要看看是否要delete这个对象了:

if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
    if (impl->mStrong == INITIAL_STRONG_VALUE)
        delete impl->mBase;
    else {
//      LOGV("Freeing refs %p of old RefBase %p\n",impl->mBase);
        delete impl;
    }
} else {
    impl->mBase->onLastWeakRef(id);
    if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
        delete impl->mBase;
    }
}

如果目标对象的生命周期是不受弱引用计数控制的,就执行下面语句:

if (impl->mStrong == INITIAL_STRONG_VALUE)
    delete impl->mBase;
else {
//  LOGV("Freeing refs %p of old RefBase %p\n",impl->mBase);
    delete impl;
}

这个代码段是什么意思呢?这里是减少对象的弱引用计数的地方,如果调用到这里,那么就说明前面一定有增加过此对象的弱引用计数,而增加对象的弱引用计数有两种场景的,一种场景是增加对象的强引用计数的时候,会同时增加对象的弱引用计数,另一种场景是当我们使用一个弱指针来指向对象时,在弱指针对象的构造函数里面,也会增加对象的弱引用计数,不过这时候,就只是增加对象的弱引用计数了,并没有同时增加对象的强引用计数。因此,这里在减少对象的弱引用计数时,就要分两种情况来考虑。

如果是前一种场景,这里的impl->mStrong就必然等于0,而不会等于INITIAL_STRONG_VALUE值,因此,这里就不需要delete目标对象了(impl->mBase),因为前面的RefBase::decStrong函数会负责delete这个对象。这里唯一需要做的就是把weakref_impl对象delete掉,但是,为什么要在这里delete这个weakref_impl对象呢?这里的weakref_impl对象是在RefBase的构造函数里面new出来的,理论上说应该在在RefBase的析构函数里delete掉这个weakref_impl对象的。在RefBase的析构函数里面,的确是会做这件事情:

RefBase::~RefBase()
{
//    LOGV("Destroying RefBase %p (refs %p)\n",mRefs);
    if (mRefs->mWeak == 0) {
//        LOGV("Freeing refs %p of old RefBase %p\n",mRefs,this);
        delete mRefs;
    }
}

但是不要忘记,在这个场景下,目标对象是前面的RefBase::decStrong函数delete掉的,这时候目标对象就会被析构,但是它的弱引用计数值尚未执行减1操作,因此,这里的mRefs->mWeak == 0条件就不成立,于是就不会delete这个weakref_impl对象,因此,就延迟到执行这里decWeak函数时再执行。

如果是后一种情景,这里的impl->mStrong值就等于INITIAL_STRONG_VALUE了,这时候由于没有地方会负责delete目标对象,因此,就需要把目标对象(imp->mBase)delete掉了,否则就会造成内存泄漏。在delete这个目标对象的时候,就会执行RefBase类的析构函数,这时候目标对象的弱引用计数等于0,于是,就会把weakref_impl对象也一起delete掉了。

回到外层的if语句中,如果目标对象的生命周期是受弱引用计数控制的,就执行下面语句:

impl->mBase->onLastWeakRef(id);
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
    delete impl->mBase;
}

理论上说,如果目标对象的生命周期是受弱引用计数控制的,那么当强引用计数和弱引用计数都为0的时候,这时候就应该delete目标对象了,但是这里还有另外一层控制,我们可以设置目标对象的标志值为OBJECT_LIFETIME_FOREVER,即目标对象的生命周期完全不受强引用计数和弱引用计数控制,在这种情况下,即使目标对象的强引用计数和弱引用计数都同时为0,这里也不能delete这个目标对象,那么,由谁来delete掉呢?当然是谁new出来的,就谁来delete掉了,这时候智能指针就完全退化为普通指针了,这里的智能指针设计的非常强大。

分析到这里,有必要小结一下:

A. 如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;

B. 如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;

C. 如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。

到了这里,强指针就分析完成了,最后来分析弱指针。

4. 弱指针

弱指针所使用的引用计数类与强指针一样,都是RefBase类,因此,这里就不再重复介绍了,我们直接来弱指针的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:

template <typename T>
class wp
{
public:
	typedef typename RefBase::weakref_type weakref_type;
 
	inline wp() : m_ptr(0) { }
 
	wp(T* other);
	wp(const wp<T>& other);
	wp(const sp<T>& other);
	template<typename U> wp(U* other);
	template<typename U> wp(const sp<U>& other);
	template<typename U> wp(const wp<U>& other);
 
	~wp();
 
	// Assignment
 
	wp& operator = (T* other);
	wp& operator = (const wp<T>& other);
	wp& operator = (const sp<T>& other);
 
	template<typename U> wp& operator = (U* other);
	template<typename U> wp& operator = (const wp<U>& other);
	template<typename U> wp& operator = (const sp<U>& other);
 
	void set_object_and_refs(T* other,weakref_type* refs);
 
	// promotion to sp
 
	sp<T> promote() const;
 
	// Reset
 
	void clear();
 
	// Accessors
 
	inline  weakref_type* get_refs() const { return m_refs; }
 
	inline  T* unsafe_get() const { return m_ptr; }
 
	// Operators
 
	COMPARE_WEAK(==)
		COMPARE_WEAK(!=)
		COMPARE_WEAK(>)
		COMPARE_WEAK(<)
		COMPARE_WEAK(<=)
		COMPARE_WEAK(>=)
 
		inline bool operator == (const wp<T>& o) const {
			return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
	}
	template<typename U>
	inline bool operator == (const wp<U>& o) const {
		return m_ptr == o.m_ptr;
	}
 
	inline bool operator > (const wp<T>& o) const {
		return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
	}
	template<typename U>
	inline bool operator > (const wp<U>& o) const {
		return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
	}
 
	inline bool operator < (const wp<T>& o) const {
		return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
	}
	template<typename U>
	inline bool operator < (const wp<U>& o) const {
		return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
	}
	inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
	template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
	inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
	template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
	inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
	template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
 
private:
	template<typename Y> friend class sp;
	template<typename Y> friend class wp;
 
	T*              m_ptr;
	weakref_type*   m_refs;
};

与强指针类相比,它们都有一个成员变量m_ptr指向目标对象,但是弱指针还有一个额外的成员变量m_refs,它的类型是weakref_type指针,下面我们分析弱指针的构造函数时再看看它是如果初始化的。这里我们需要关注的仍然是弱指针的构造函数和析构函数。

先来看构造函数:

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

这里的参数other一定是继承了RefBase类,因此,这里调用了RefBase类的createWeak函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:

RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}

这里的成员变量mRefs的类型为weakref_impl指针,weakref_impl类的incWeak函数我们在前面已经看过了,它的作用就是增加对象的弱引用计数。函数最后返回mRefs,于是,弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。

再来看析构函数:

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}

这里,弱指针在析构的时候,与强指针析构不一样,它直接就调用目标对象的weakref_impl对象的decWeak函数来减少弱引用计数了,当弱引用计数为0的时候,就会根据在目标对象的标志位(0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER)来决定是否要delete目标对象,前面我们已经介绍过了,这里就不再介绍了。

分析到这里,弱指针还没介绍完,它最重要的特性我们还没有分析到。前面我们说过,弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了:

template<typename T>
sp<T> wp<T>::promote() const
{
    return sp<T>(m_ptr,m_refs);
}

升级的方式就使用成员变量m_ptr和m_refs来构造一个强指针sp,这里的m_ptr为指目标对象的一个指针,而m_refs则是指向目标对象里面的weakref_impl对象。

我们再来看看这个强指针的构造过程:

template<typename T>
sp<T>::sp(T* p,weakref_type* refs)
    : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}

主要就是初始化指向目标对象的成员变量m_ptr了,如果目标对象还存在,这个m_ptr就指向目标对象,如果目标对象已经不存在,m_ptr就为NULL,升级成功与否就要看refs->attemptIncStrong函数的返回结果了:

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
	incWeak(id);
 
	weakref_impl* const impl = static_cast<weakref_impl*>(this);
 
	int32_t curCount = impl->mStrong;
	LOG_ASSERT(curCount >= 0,"attemptIncStrong called on %p after underflow",this);
	while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
		if (android_atomic_cmpxchg(curCount,curCount+1,&impl->mStrong) == 0) {
			break;
		}
		curCount = impl->mStrong;
	}
 
	if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
		bool allow;
		if (curCount == INITIAL_STRONG_VALUE) {
			// Attempting to acquire first strong reference...  this is allowed
			// if the object does NOT have a longer lifetime (meaning the
			// implementation doesn't need to see this),or if the implementation
			// allows it to happen.
			allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
				|| impl->mBase->onIncStrongAttempted(FirsT_INC_STRONG,id);
		} else {
			// Attempting to revive the object...  this is allowed
			// if the object DOES have a longer lifetime (so we can safely
			// call the object with only a weak ref) and the implementation
			// allows it to happen.
			allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
				&& impl->mBase->onIncStrongAttempted(FirsT_INC_STRONG,id);
		}
		if (!allow) {
			decWeak(id);
			return false;
		}
		curCount = android_atomic_inc(&impl->mStrong);
 
		// If the strong reference count has already been incremented by
		// someone else,the implementor of onIncStrongAttempted() is holding
		// an unneeded reference.  So call onLastStrongRef() here to remove it.
		// (No,this is not pretty.)  Note that we MUST NOT do this if we
		// are in fact acquiring the first reference.
		if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
			impl->mBase->onLastStrongRef(id);
		}
	}
 
	impl->addWeakRef(id);
	impl->addStrongRef(id);
 
#if PRINT_REFS
	LOGD("attemptIncStrong of %p from %p: cnt=%d\n",curCount);
#endif
 
	if (curCount == INITIAL_STRONG_VALUE) {
		android_atomic_add(-INITIAL_STRONG_VALUE,&impl->mStrong);
		impl->mBase->onFirstRef();
	}
 
	return true;
}

这个函数的作用是试图增加目标对象的强引用计数,但是有可能会失败,失败的原因可能是因为目标对象已经被delete掉了,或者是其它的原因,下面会分析到。前面我们在讨论强指针的时候说到,增加目标对象的强引用计数的同时,也会增加目标对象的弱引用计数,因此,函数在开始的地方首先就是调用incWeak函数来先增加目标对象的引用计数,如果后面试图增加目标对象的强引用计数失败时,会调用decWeak函数来回滚前面的incWeak操作。

这里试图增加目标对象的强引用计数时,分两种情况讨论,一种情况是此时目标对象正在被其它强指针引用,即它的强引用计数大于0,并且不等于INITIAL_STRONG_VALUE,另一种情况是此时目标对象没有被任何强指针引用,即它的强引用计数小于等于0,或者等于INITIAL_STRONG_VALUE。

第一种情况比较简单,因为这时候说明目标对象一定存在,因此,是可以将这个弱指针提升为强指针的,在这种情况下,只要简单地增加目标对象的强引用计数值就行了:

while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
if (android_atomic_cmpxchg(curCount,&impl->mStrong) == 0) {
	break;
}
curCount = impl->mStrong;
}

当我们在这里对目标对象的强引用计数执行加1操作时,要保证原子性,因为其它地方也有可能正在对这个目标对象的强引用计数执行加1的操作,前面我们一般是调用android_atomic_inc函数来完成,但是这里是通过调用android_atomic_cmpxchg函数来完成,android_atomic_cmpxchg函数是体系结构相关的函数,在提供了一些特殊的指令的体系结构上,调用android_atomic_cmpxchg函数来执行加1操作的效率会比调用android_atomic_inc函数更高一些。函数android_atomic_cmpxchg是在system/core/include/cutils/atomic.h文件中定义的一个宏:

int android_atomic_release_cas(int32_t oldvalue,int32_t newvalue,volatile int32_t* addr);
 
#define android_atomic_cmpxchg android_atomic_release_cas

它实际执行的函数是android_atomic_release_cas,这个函数的工作原理大概是这样的:如果它发现addr == oldvalue,就会执行addr = newvalue的操作,然后返回0,否则什么也不做,返回1。在我们讨论的这个场景中,oldvalue等于curCount,而newvalue等于curCount + 1,于是,在addr == oldvalue的条件下,就相当于是对目标对象的强引用计数值增加了1。什么情况下addr != oldvalue呢?在调用android_atomic_release_cas函数之前,oldvalue和值就是从地址addr读出来的,如果在执行android_atomic_release_cas函数的时候,有其它地方也对地址addr进行操作,那么就会有可能出现*addr != oldvalue的情况,这时候就说明其它地方也在操作目标对象的强引用计数了,因此,这里就不能执行增加目标对象的强引用计数的操作了,它必须要等到其它地方操作完目标对象的强引用计数之后再重新执行,这就是为什么要通过一个while循环来执行了。

第二种情况比较复杂一点,因为这时候目标对象可能还存在,也可能不存了,这要根据实际情况来判断。如果此时目标对象的强引用计数值等于INITIAL_STRONG_VALUE,说明此目标对象还从未被强指针引用过,这时候弱指针能够被提升为强指针的条件就为:

allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
	|| impl->mBase->onIncStrongAttempted(FirsT_INC_STRONG,id);

即如果目标对象的生命周期只受到强引用计数控制或者在目标对象的具体实现中总是允许这种情况发生。怎么理解呢?如果目标对象的生命周期只受强引用计数控制(它的标志位mFlags为0),而这时目标对象又还未被强指针引用过,它自然就不会被delete掉,因此,这时候可以判断出目标对象是存在的;如果目标对象的生命周期受弱引用计数控制(OBJECT_LIFETIME_WEAK),这时候由于目标对象正在被弱指针引用,因此,弱引用计数一定不为0,目标对象一定存在;如果目标对象的生命周期不受引用计数控制(BJECT_LIFETIME_FOREVER),这时候目标对象也是下在被弱指针引用,因此,目标对象的所有者必须保证这个目标对象还没有被delete掉,否则就会出问题了。在后面两种场景下,因为目标对象的生命周期都是不受强引用计数控制的,而现在又要把弱指针提升为强指针,就需要进一步调用目标对象的onIncStrongAttempted来看看是否允许这种情况发生,这又该怎么理解呢?可以这样理解,目标对象的设计者可能本身就不希望这个对象被强指针引用,只能通过弱指针来引用它,因此,这里它就可以重载其父类的onIncStrongAttempted函数,然后返回false,这样就可以阻止弱指针都被提升为强指针。在RefBase类中,其成员函数onIncStrongAttempted默认是返回true的:

bool RefBase::onIncStrongAttempted(uint32_t flags,const void* id)
{
    return (flags&FirsT_INC_STRONG) ? true : false;
}

如果此时目标对象的强引用计数值小于等于0,那就说明该对象之前一定被强指针引用过,这时候就必须保证目标对象是被弱引用计数控制的(BJECT_LIFETIME_WEAK),否则的话,目标对象就已经被delete了。同样,这里也要调用一下目标对象的onIncStrongAttempted成员函数,来询问一下目标对象在强引用计数值小于等于0的时候,是否允计将弱指针提升为强指针。下面这个代码段就是执行上面所说的逻辑:

allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
	&& impl->mBase->onIncStrongAttempted(FirsT_INC_STRONG,id);

继续往下看:

if (!allow) {
	decWeak(id);
	return false;
}
curCount = android_atomic_inc(&impl->mStrong);

如果allow值为false,那么就说明不允计把这个弱指针提升为强指针,因此就返回false了,在返回之前,要先调用decWeak函数来减少目标对象的弱引用计数,因为函数的开头不管三七二十一,首先就调用了incWeak来增加目标对象的弱引用计数值。

函数attemptIncStrong的主体逻辑大概就是这样了,比较复杂,读者要细细体会一下。函数的最后,如果此弱指针是允计提升为强指针的,并且此目标对象是第一次被强指针引用,还需要调整一下目标对象的强引用计数值:

if (curCount == INITIAL_STRONG_VALUE) {
	android_atomic_add(-INITIAL_STRONG_VALUE,&impl->mStrong);
	impl->mBase->onFirstRef();
}

这个逻辑我们在前面分析强指针时已经分析过了,这里不再详述。

分析到这里,弱指针就介绍完了。强指针和弱指针的关系比较密切,同时它们也比较复杂,下面我们再举一个例子来说明强指针和弱指针的用法,同时也验证一下它们的实现原理。

5. 强指针和弱指针的用法

参考在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序一文,我们在external目录下建立一个C++工程目录weightpointer,它里面有两个文件,一个weightpointer.cpp文件,另外一个是Android.mk文件。

源文件weightpointer.cpp的内容如下:

#include <stdio.h>
#include <utils/RefBase.h>
 
#define INITIAL_STRONG_VALUE (1<<28)
 
using namespace android;
 
class WeightClass : public RefBase
{
public:
        void printRefCount()
        {
                int32_t strong = getStrongCount();
                weakref_type* ref = getWeakRefs();
 
                printf("-----------------------\n");
                printf("Strong Ref Count: %d.\n",(strong  == INITIAL_STRONG_VALUE ? 0 : strong));
                printf("Weak Ref Count: %d.\n",ref->getWeakCount());
                printf("-----------------------\n");
        }
};
 
class StrongClass : public WeightClass
{
public:
        StrongClass()
        {
                printf("Construct StrongClass Object.\n");
        }
 
        virtual ~StrongClass()
        {
                printf("Destory StrongClass Object.\n");
        }
};
 
 
class WeakClass : public WeightClass
{
public:
        WeakClass()
        {
                extendobjectLifetime(OBJECT_LIFETIME_WEAK);
 
                printf("Construct WeakClass Object.\n");
        }
 
        virtual ~WeakClass()
        {
                printf("Destory WeakClass Object.\n");
        }
};
 
class ForeverClass : public WeightClass
{
public:
        ForeverClass()
        {
                extendobjectLifetime(OBJECT_LIFETIME_FOREVER);
 
                printf("Construct ForeverClass Object.\n");
        }
 
        virtual ~ForeverClass()
        {
                printf("Destory ForeverClass Object.\n");
        }
};
 
 
void TestStrongClass(StrongClass* pStrongClass)
{
        wp<StrongClass> wpOut = pStrongClass;
        pStrongClass->printRefCount();
 
        {
                sp<StrongClass> spInner = pStrongClass;
                pStrongClass->printRefCount();
        }
 
        sp<StrongClass> spout = wpOut.promote();
        printf("spout: %p.\n",spout.get());
}
 
void TestWeakClass(WeakClass* pWeakClass)
{
        wp<WeakClass> wpOut = pWeakClass;
        pWeakClass->printRefCount();
 
        {
                sp<WeakClass> spInner = pWeakClass;
                pWeakClass->printRefCount();
        }
 
        pWeakClass->printRefCount();
        sp<WeakClass> spout = wpOut.promote();
        printf("spout: %p.\n",spout.get());
}
 
 
void TestForeverClass(ForeverClass* pForeverClass)
{
        wp<ForeverClass> wpOut = pForeverClass;
        pForeverClass->printRefCount();
 
        {
                sp<ForeverClass> spInner = pForeverClass;
                pForeverClass->printRefCount();
        }
}
 
int main(int argc,char** argv)
{
        printf("Test Strong Class: \n");
        StrongClass* pStrongClass = new StrongClass();
        TestStrongClass(pStrongClass);
 
        printf("\nTest Weak Class: \n");
        WeakClass* pWeakClass = new WeakClass();
        TestWeakClass(pWeakClass);
 
        printf("\nTest Froever Class: \n");
        ForeverClass* pForeverClass = new ForeverClass();
        TestForeverClass(pForeverClass);
        pForeverClass->printRefCount();
        delete pForeverClass;
 
        return 0;
}

首先定义了一个基类WeightClass,继承于RefBase类,它只有一个成员函数printRefCount,作用是用来输出引用计数。接着分别定义了三个类StrongClass、WeakClass和ForeverClass,其中实例化StrongClass类的得到的对象的标志位为默认值0,实例化WeakClass类的得到的对象的标志位为OBJECT_LIFETIME_WEAK,实例化ForeverClass类的得到的对象的标志位为OBJECT_LIFETIME_FOREVER,后两者都是通过调用RefBase类的extendobjectLifetime成员函数来设置的。

在main函数里面,分别实例化了这三个类的对象出来,然后分别传给TestStrongClass函数、TestWeakClass函数和TestForeverClass函数来说明智能指针的用法,我们主要是通过考察它们的强引用计数和弱引用计数来验证智能指针的实现原理。

编译脚本文件Android.mk的内容如下:


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := weightpointer
LOCAL_SRC_FILES := weightpointer.cpp
LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libutils
include $(BUILD_EXECUTABLE)

最后,我们参照如何单独编译Android源代码中的模块一文,使用mmm命令对工程进行编译:

USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer

编译之后,就可以打包了:

USER-NAME@MACHINE-NAME:~/Android$ make snod

最后得到可执行程序weightpointer就位于设备上的/system/bin/目录下。启动模拟器,通过adb shell命令进入到模拟器终端,进入到/system/bin/目录,执行weightpointer可执行程序,验证程序是否按照我们设计的逻辑运行:

USER-NAME@MACHINE-NAME:~/Android$ adb shell
root@android:/ # cd system/bin/        
root@android:/system/bin # ./weightpointer  

执行TestStrongClass函数的输出为:

Test Strong Class: 
Construct StrongClass Object.
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------
Destory StrongClass Object.
spout: 0x0.

在TestStrongClass函数里面,首先定义一个弱批针wpOut指向从main函数传进来的StrongClass对象,这时候我们可以看到StrongClass对象的强引用计数和弱引用计数值分别为0和1;接着在一个大括号里面定义一个强指针spInner指向这个StrongClass对象,这时候我们可以看到StrongClass对象的强引用计数和弱引用计数值分别为1和2;当程序跳出了大括号之后,强指针spInner就被析构了,从上面的分析我们知道,强指针spInner析构时,会减少目标对象的强引用计数值,因为前面得到的强引用计数值为1,这里减1后,就变为0了,又由于这个StrongClass对象的生命周期只受强引用计数控制,因此,这个StrongClass对象就被delete了,这一点可以从后面的输出(“Destory StrongClass Object.”)以及试图把弱指针wpOut提升为强指针时得到的对象指针为0x0得到验证。

执行TestWeakClass函数的输出为:

Test Weak Class: 
Construct WeakClass Object.
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
spout: 0xa528.
Destory WeakClass Object.

TestWeakClass函数和TestStrongClass函数的执行过程基本一样,所不同的是当程序跳出大括号之后,虽然这个WeakClass对象的强引用计数值已经为0,但是由于它的生命周期同时受强引用计数和弱引用计数控制,而这时它的弱引用计数值大于0,因此,这个WeakClass对象不会被delete掉,这一点可以从后面试图把弱批针wpOut提升为强指针时得到的对象指针不为0得到验证。

执行TestForeverClass函数的输出来:

Test Froever Class: 
Construct ForeverClass Object.
-----------------------
Strong Ref Count: 0.
Weak Ref Count: 1.
-----------------------
-----------------------
Strong Ref Count: 1.
Weak Ref Count: 2.
-----------------------

当执行完TestForeverClass函数返回到main函数的输出来:

-----------------------
Strong Ref Count: 0.
Weak Ref Count: 0.
-----------------------
Destory ForeverClass Object.

这里我们可以看出,虽然这个ForeverClass对象的强引用计数和弱引用计数值均为0了,但是它不自动被delete掉,虽然由我们手动地delete这个对象,它才会被析构,这是因为这个ForeverClass对象的生命周期是既不受强引用计数值控制,也不会弱引用计数值控制。

这样,从TestStrongClass、TestWeakClass和TestForeverClass这三个函数的输出就可以验证了我们上面对Android系统的强指针和弱指针的实现原理的分析。

6. 强弱指针的对比

  • 通过类图可以发现,强指针实现了 “.” “->” 操作符的重载,因此sp 可以直接方位类成员,而wp 却不能,
  • 但是wp 可以转化为sp

至此,Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理就分析完成了,它实现得很小巧但是很精致,希望读者可以通过实际操作细细体会一下。

关于套接字 – 带addrinfo结构的智能指针套接字实现原理的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Android 中的智能指针、Android 系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析、android中的智能指针、Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析的相关知识,请在本站寻找。

本文标签: