Android智能指针

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/readlnh/article/details/82844435

Android智能指针

Android和gecko底层都是由c++来实现的,而c++最头痛的就是内存泄漏问题了,常见的c++项目中的指针问题基本上有以下几种:

  • 指针没有初始化

  • new了对象后没有及时delete

  • 野指针

智能指针需要做什么

智能指针就是用来解决上面的这些问题的。

  • 首先智能指针必须解决初始化问题,这个问题比较简单,只要让指针在创建的时候设置值为null即可(比如,把智能指针设计为一个类,通过构造函数来初始化)

  • 其次智能指针需要实现new和delete的配套,即new了对象后要及时的delete掉。这个过程必须自动(否则就不叫智能了)。即智能指针必须能判断某一块内存是否需要回收。

假定智能指针为SmartPoint,所指对象为object,那么显然其实现应该如下

template <typename T>
class SmartPoint
{
public:
	inline SmartPoint() : m_ptr(0) {} //构造函数初始化
private:
	T* m_ptr; //指向object对象
}

但是什么时候释放内存呢,当然是“当不需要的时候”。什么时候是不需要的时候呢?思考一下,我们可以得出:如果有一个指针指向object,那就代表后者是被需要的;而如果一个对象没有指针指向它,那就是不被需要的(已经不需要了)。这种时候这个对象就应该被释放。
考虑到可能有两个以上的指针指向一个对象,只需要有一个计数器来记录该内存对象被需要的个数,如果计数器为0,则说明这个对象已经不被需要了。这个概念就是在很多领域都广泛应用的“引用计数”了。
那么现在来考虑下,计数器应该由谁来管理呢?

  • 智能指针
  • object自身

如果由智能指针拥有计数器,如果一个对象只有一个指针指向它,那没什么问题,但是如果有多个指针,多个指针之间并不能知道其他指针是否还指向对象,无法判断对象什么时候能释放,故计数器只能由object(对象)自身来管理。

安卓的LightRefBase类

我们为有计数器需求的对象实现一个含有计数器的统一的“父类”,这样只要object继承了该父类,它就具备了计数器的功能。安卓中就实现了一个LightRefBase类

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

    typedef LightRefBase<T> basetype;

protected:
    inline ~LightRefBase() { }

private:
    friend class ReferenceMover;
    inline static void moveReferences(void*, void const*, size_t,
            const ReferenceConverterBase&) { }

private:
    mutable volatile int32_t mCount;
};

LightRefBase类主要有两个方法 incStrongdecStrong,分别用来加减计数器;其中decStrong还需要在计数器为0 的时候释放内存(即不被需要了)。
显然incStrong会在对象被引用时被调用,故应该重载智能指针的=等符号,当引用对象时调用incStrong,同理,智能指针析构时也应该调用decStrong。具体的例子可以参照android中sp(强指针)的实现。

强指针sp(Strong Point)

以下路径有sp 的源码

./system/core/include/utils/StrongPointer.h
./frameworks/rs/cpp/util/StrongPointer.h
./frameworks/rs/server/StrongPointer.h

先来看看sp的类

template <typename T>
class sp
{
public:
    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;
    void set_pointer(T* ptr);
    T* m_ptr;
};

可以看到其中的接口基本和我们分析的一致,比如其中运算符重载:

template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
    if (other) other->incStrong(this);
    if (m_ptr) m_ptr->decStrong(this);
    m_ptr = other;
    return *this;
}

注意这里考虑了对一个智能指针重复赋值的情况,如果m_ptr不为空,要先撤销它之前指向的内存对象,然后才能赋新值。
另,sp分配内存对象不一定是通过运算符,比如构造函数:

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

当然因为是构造函数,m_ptr之前必定没有赋过值。
析构函数同理

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

弱指针wp

弱引用是一个对象引用的持有者,使用弱引用后可以维持对对象的引用,但是不会阻止其被垃圾回收。如果一个对象只有弱引用了,那它就成为被垃圾回收的候选对象,就像没有剩余的引用一样,而且一旦对象被删除,所有的弱引用也会被清除

Android6.0源码中RefBase源文件出现的位置

Android6.0中源码位置和Android4.3已经不同

./prebuilts/ndk/9/platforms/android-19/arch-x86/usr/include/rs/cpp/util/RefBase.h
./prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/rs/cpp/util/RefBase.h
./prebuilts/ndk/9/platforms/android-19/arch-mips/usr/include/rs/cpp/util/RefBase.h
./system/core/include/utils/RefBase.h
./system/core/libutils/RefBase.cpp
./frameworks/rs/cpp/util/RefBase.h
./frameworks/rs/server/RefBase.h

猜你喜欢

转载自blog.csdn.net/readlnh/article/details/82844435