Android 系统C++智能指针----总结

1、前言

想要成为一名优秀的Android开发者, 咱们避免不了要深刻Android系统进行学习。只有搞明白了Android系统的运行机制、原理,咱们才能更加驾轻就熟的开发出性能优越的Android应用。android

固然,在进行深刻学习以前咱们也须要具备必定的基础(例如:C++),想要深刻学习Android系统的朋友们仍是有必要先去学习C++的。由于在Android底层不少的核心功能都是使用C++开发出来的。web

2、什么是智能指针?

使用过C++的朋友确定都知道C++的指针,使用起来很是方便,功能强大。可是也有不足之处,就是咱们必须本身去管理指针的释放,不然就会形成内存泄漏甚至程序崩溃。编程

那么Android在使用C++的时候, 提供了一个很方便的工具,就是智能指针。目的是帮助咱们来进行对象的释放工做。其使用的基本原理就是引用计数法。
咱们能够对智能指针作一些总结:安全

  • 一种可以自动维护对象引用计数的技术
  • 智能指针一是个对象,而不是一个指针
  • 智能指针分为强指针、弱指针
  • Android定义了一个公共基类,全部想要使用智能指针的类都要继承它

3、智能指针的公共基类

Android OS 8.0.0_r4
/system/core/include/utils/RefBase.h多线程

class RefBase
{
public:
            void            incStrong(const void* id) const; // 增长强引用
            void            decStrong(const void* id) const; // 减小强引用
			
			// ... 

			// 内部类表示弱引用类型
		    class weakref_type
		    {
		    public:
		        RefBase*            refBase() const;
		        void                incWeak(const void* id); // 增长弱引用
		        void                decWeak(const void* id); // 减小弱引用
		        bool                attemptIncStrong(const void* id); // 尝试获取强引用对象,在弱引用升级强引用时会调用
		    };

            weakref_type*   createWeak(const void* id) const;  // 建立弱引用
            weakref_type*   getWeakRefs() const;
			typedef RefBase basetype;

protected使用:
                            RefBase();
   virtual                 ~RefBase();//  虚析构函数,子类也要使用虚析构函数,当基类指针指向派生对象时, 若是不是虚析构函数,delete不会调用派生对象的析构函数,就有可能形成泄露
    
    //标记生命周期的模式
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000, // 生命周期只跟强引用有关, 当强引用为0时释放对象
        OBJECT_LIFETIME_WEAK    = 0x0001, // 生命周期只跟弱引用有关, 当弱引用为0时释放对象
        OBJECT_LIFETIME_MASK    = 0x0001
    };
    
    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;						 // 声明类 weakref_impl
               RefBase(const RefBase& o); 	 // 构造方法
    RefBase&   operator=(const RefBase& o);  // 重载运算符: =

private:
        weakref_impl* const mRefs; // 持有一个类weakref_impl的对象,用来管理强/弱引用计数
};

咱们上面说到, 智能指针使用的是引用计数法。那么在上面好像并无看到用来计数的变量。
其实RefBase使用的是weakref_impl来维护强引用计数和弱引用计数的。咱们下面看一下weakref_impl的代码。app

/system/core/libutils/RefBase.cppsvg

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) // 强引用计数初始化的值, 不是0
        , 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
};

上面一共看到了三个类,RefBase、weakref_type、weakref_impl。
每个RefBase对象都包含了一个weakref_impl对象,而weakref_impl继承了weakref_type。函数

当咱们本身的类想要使用智能指针的时候, 只须要继承RefBase就能够了。这样咱们的类就拥有了weakref_impl类型的成员变量, 用来维护当前对象的引用计数。当咱们把对象赋值给强指针(sp<>)或者弱指针(wp<>)的时候, 就能够不用去管理强弱指针的释放工做了, 不用的时候只须要给强弱指针赋值为NULL就能够了。工具

4、智能指针的强指针实现类

/system/core/include/utils/StrongPointer.h性能

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是上面定义的宏, 把对应的运算都转换成了m_ptr指针的运算
    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; // 强引用指针引用的真实对象
};

强指针类的实现也比较简单,就是持有了真实对象的指针, 而后重载了不少运算符, 在构造和析构时分别增长减小引用数量。

咱们看一下它的构造和析构方法

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this); // 调用存储对象的incStrong()来增长强指针计数
}

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);// 调用存储对象的decStrong()来减小强指针计数
}

在构造函数和析构函数中分别调用了incStrong()和decStrong()来增长减小引用计数。这两个方法定义在智能指针的基类RefBase中。咱们前面提到过, 全部想要使用智能指针的类都须要继承RefBase。接下来咱们去看一下这两个方法的具体实现。

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs; // 成员变量mRefs,负责管理强弱引用的计数
   
    refs->incWeak(id); // 每次增长强引用计数都要增长弱引用计数, 因此弱引用计数的值大于等于强引用计数的值
   
    refs->addStrongRef(id); // 非调试模式下是空实现, 能够忽略
    
    const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed); // 强引用计数值增1, 返回老的计数值
	
    if (c != INITIAL_STRONG_VALUE)  {// 若是老的计数值不等于初始化的指, 表明不是第一次增长强引用,到这里就直接返回了
        return;
    }

	// 若是这是第一次增长强引用的值, 须要减去初始值( #define INITIAL_STRONG_VALUE (1<<28) ) , 这样第一次的计数值就是1了
    int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
    // 上面提到的引用计数变化的回调函数,  onFirstRef: 第一次增长强引用计数
    refs->mBase->onFirstRef();
}

每次调用incStrong来增长强引用计数的时候, 都会同时增长弱引用计数的值。
这里有一点就是, 强引用计数值的初始值不是0, 是INITIAL_STRONG_VALUE (1<<28),这是为了区分是没有增长过, 仍是说已经增长过,又减到1了的状况。

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); // 强引用计数值减1, 返回减1前的值

	// 若是减1前的值 == 1, 表明当前的强引用计数为0了, 就能够回收了
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire); // 用来保证线程同步的, 
        refs->mBase->onLastStrongRef(id); // 回调方法 onLastStrongRef, 子类能够复写, 来实现一些业务
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        // 判断生命周期类型的标记
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        	// 表示生命周期只受强引用计数影响, 当前强引用计数为0, 就须要释放对象内存了
            delete this; // 会调用RefBase类的析构函数
            // 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);
}

当调用decStrong来减小强引用计数的时候, 若是本次减小后, 计数为0了。就会去判断对象生命周期是不是受强引用计数影响, 若是是就会使用delete来回收对象,触发对象的析构函数。

最后会调用decWeak() 来减小弱引用计数

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release); // 弱引用减1
    
    if (c != 1) return; // 不是最后一个弱引用就直接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) { 
        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 {
       		 // 此处释放引用计数对象weakref_impl
            // 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);
         // 若是是受弱引用影响的生命周期, 这次触发RefBase的析构函数, 在RefBase的析构函数中会释放impl
        delete impl->mBase;
        
    }
}

咱们来看一下RefBase的析构函数

RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);// 取出生命周期类型标记
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {// 受弱引用影响的时候
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) { // 当弱引用也等于0时,释放它的成员变量 mRefs
            delete mRefs;
        }
    }
     else if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {// 历来没有增长过强引用计数的值, 异常状况  delete mRefs;
        // 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;
}

强引用实现原理小结:

  1. 强引用指针对象在使用的时候, 只须要初始化成对象就好, 不要初始化成指针类型。咱们是在这个对象的成员变量中保存了真实对象的指针。
  2. 能够把这个对象看成指针来使用, 由于对各类运算符都作了重载。
  3. 当生命周期受强引用影响时,强引用计数减小为0时会去主动释放当前对象,可是并不会去释放mRefs。
  4. 当生命周期受弱引用影响时,强引用计数减小为0时,不会触发析构函数回收对象。只有在弱引用计数值也变为0时,才会回收对象。

5、弱引用计数实现原理

弱引用的实现稍微复杂一点, 由于弱引用不能够直接访问它所引用的对象, 只能尝试升级为强引用才能访问它所引用的对象。 升级失败表明对象已被回收, 升级成功则能够正常访问。

弱引用指针的实现类

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;// 用weakref_type 表示  RefBase::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;
};

具体实现跟强引用实现类sp很像, 只是少了 * 和 -> 的运算符重载, 这样咱们就没有办法直接经过弱引用来访问真实的对象了。多了一个
sp promote() const;
来实现把弱引用升级为强引用, 这样就能够访问所引用的对象了。

接下来咱们先来看一下wp的构成函数。

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

给指针m_ptr赋值, 而后调用它的createWeak来建立引用对象m_refs

createWeak方法在RefBase中声明, 返回一个weakref_type

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

mRefs就是一个weakref_impl的对象, 咱们来看一下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);
}

能够看到实现很简单, 就是给弱引用mWeak的值增1

当咱们想要访问弱引用的对象时, 须要先把弱引用升级为强引用才能够访问。
升级为强引用须要调用promote()方法, 下面看一下它的具体实现。

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

当m_ptr存在时, 调用了weakref_type的方法attemptIncStrong(), 来尝试升级为强引用。升级成功后, 使用强引用的set_pointer()方法把引用对象赋值给强引用对象,而后返回强引用对象。

template<typename T>
void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr; // 由于有重载赋值运算符, 因此会增长强引用。
}

下面看一下attemptIncStrong()的具体实现

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id); // 弱引用+1
    
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);// 取出当前强引用的值
    
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {// 当前强引用大于0, 且不是初始值
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1, std::memory_order_relaxed)) {
        	// 强引用+1,保证线程安全,+1成功后,跳出循环。
            break;
        }
    }
    
    // 若是此时的强引用计数指小于等于0, 或者是初始值
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);// 取出标记位

		// 对象的强引用不是初始值, 表示该对象已经被回收了, 升级强引用失败, 弱引用-1
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            if (curCount <= 0) {
                decWeak(id);
                return false;
            }

			// 强引用是初始值, 强引用+1, 成功后跳出循环
            while (curCount > 0) {
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1, std::memory_order_relaxed)) {
                    break;
                }
            }
            
            if (curCount <= 0) { // 升级失败, 有别的线程释放了对象。
                decWeak(id);
                return false;
            }
        } 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;
            }
            // 强引用+1
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            // 从弱引用恢复的回调函数
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                impl->mBase->onLastStrongRef(id);
            }
        }
    }

    // curCount 是咱们增长以前的指, 若是是初始值, 那么须要减去初始值, 这样强引用计数的值才为1
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}

总结:

  1. 弱引用不可以直接访问对象,须要尝试升级为强引用才能够访问对象。
  2. 若是对象生命周期受强引用影响, 那么升级的时候, 若是强引用为0则升级失败, 若是是初始值,则能够升级成功(中间还会判断一次,有没有别的线程回收了该对象)
  3. 若是生命周期受弱引用影响, 会调用onIncStrongAttempted()来判断是否容许升级强引用。容许则升级强引用, 增长强引用计数,返回true。
  4. 弱引用之因此不能直接访问对象是由于没有重载*和->运算符。

6、结束语

智能指针的实现仍是比较简单的, 能够本身去看一看源代码。这里主要是对本身C++语言的一个检验。里面用到了C++中的一些基础知识: 构造函数、析构函数、模板、友元、运算符重载等。
还牵扯到C++多线程的一些知识点:

原子数据模板类:atomic<T>

C++ 并行编程: 设定 指令执行顺序

typedef enum memory_order {
    memory_order_relaxed,    // 不对执行顺序作保证
    memory_order_acquire,    // 本线程中,全部后续的读操做必须在本条原子操做完成后执行
    memory_order_release,    // 本线程中,全部以前的写操做完成后才能执行本条原子操做
    memory_order_acq_rel,    // 同时包含 memory_order_acquire 和 memory_order_release
    memory_order_consume,    // 本线程中,全部后续的有关本原子类型的操做,必须在本条原子操做完成以后执行
    memory_order_seq_cst    // 所有存取都按顺序执行
    } memory_order;

最后附上能够查看源码的连接:
版本: android os 8.0.0_r4
RefBase.h
RefBase.cpp
StrongPointer.h