Android自己的智能指针

智能指针是一种抽象的数据类型,它通常是通过类模板实现的,可以实现泛型,并且可以通过类的析构函数自动释放指针所指向的内存或对象。

在Android中,有类似 shared_ptrweak_ptr 的智能指针 LightRefBase + spRefBase + wp

其中:

LightRefBase + sp 类似于 shared_ptr 的实际使用方法;

RefBase + wp + sp 类似于 shared_ptr + weak_ptr 的实际使用方法。

weak_ptr 是配合 shared_ptr 使用的,详细可以查看C++四种智能指针

实际原理就是:

通过引用计数来维护对象的生命周期。每当一个新的指针指向了一个对象时,这个对象的引用计数就增加1,相反每当一个指针不再指向一个对象时,这个对象的引用计数就减少1,当引用计数为0的时候,就安全的释放它。

为了避免循环引用。需要自己控制在合适的位置使用 weak 引用。weak 引用不会增加引用计数(这是在C++11中。 在android中,strong引用 和 weak引用 的计数是分开保存的。当然原理一致。只看强引用)

下面的代码基本都在 system/core 目录下,本文中的代码来自android 13 。就不一一详细标明了。

1、LightRefBase + sp

LightRefBase 是一个模板类,内部通过成员变量mCount来对引用进行计数,incStrong方法对mCount加1,decStrong方法对mCount减1。如果不涉及循环引用。直接继承类LightRefBase使用即可。

arduino 复制代码
template <class T>
class LightRefBase
{
public:
    // 构造函数初始化引用计数为0
    inline LightRefBase() : mCount(0) { }
    // 引用计数变量加1
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    // 引用计数减1
    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);
            // 当引用计数器减到0的时候通过del释放原本对象
            delete static_cast<const T*>(this);
        }
    }
    // 获取引用计数值
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }
    typedef LightRefBase<T> basetype;
protected:
    inline ~LightRefBase() { }
private:
    // 引用计数成员变量
    mutable std::atomic<int32_t> mCount;
};

sp是轻量级指针的实现类,同时也是强指针的实现类。构造函数+1,析构函数-1。

优点:简单方便,能覆盖大多数场景

缺点:有循环引用导致无法释放,进而导致内存泄漏问题。

arduino 复制代码
template<typename T>
class sp {
public:
    inline sp() : m_ptr(nullptr) { }

    // The old way of using sp<> was like this. This is bad because it relies
    // on implicit conversion to sp<>, which we would like to remove (if an
    // object is being managed some other way, this is double-ownership). We
    // want to move away from this:
    //
    //     sp<Foo> foo = new Foo(...); // DO NOT DO THIS
    //
    // Instead, prefer to do this:
    //
    //     sp<Foo> foo = sp<Foo>::make(...); // DO THIS
    //
    // Sometimes, in order to use this, when a constructor is marked as private,
    // you may need to add this to your class:
    //
    //     friend class sp<Foo>;
    template <typename... Args>
    static inline sp<T> make(Args&&... args);

    // if nullptr, returns nullptr
    //
    // if a strong pointer is already available, this will retrieve it,
    // otherwise, this will abort
    static inline sp<T> fromExisting(T* other);

    // for more information about this macro and correct RefBase usage, see
    // the comment at the top of utils/RefBase.h
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
    sp(std::nullptr_t) : sp() {}
#else
    sp(T* other);  // NOLINT(implicit)
    template <typename U>
    sp(U* other);  // NOLINT(implicit)
    sp& operator=(T* other);
    template <typename U>
    sp& operator=(U* other);
#endif

    sp(const sp<T>& other);
    sp(sp<T>&& other) noexcept;

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

    // Cast a strong pointer directly from one type to another. Constructors
    // allow changing types, but only if they are pointer-compatible. This does
    // a static_cast internally.
    template <typename U>
    static inline sp<T> cast(const sp<U>& other);

    ~sp();

    // Assignment

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

    template<typename U> sp& operator = (const sp<U>& other);
    template<typename U> sp& operator = (sp<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; }
    inline explicit operator bool () const { return m_ptr != nullptr; }

    // Punt these to the wp<> implementation.
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return o == *this;
    }

    template<typename U>
    inline bool operator != (const wp<U>& o) const {
        return o != *this;
    }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    static inline void check_not_on_stack(const void* ptr);
    T* m_ptr;
};


template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
        : m_ptr(other.m_ptr) {
    if (m_ptr)
        m_ptr->incStrong(this);
}

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

2、RefBase + wp + sp

RefBase 也是模板类,其中,强引用的计数,提供了incStrong和decStrong方法来维护;弱引用的计数提供了incWeak和decWeak方法。同时它使用weakref_type类的对象来描述对象的引用计数,该类实现类为weakref_impl。因此同时需要使用强指针或者弱指针(也就是要考虑内存泄漏的可能情况),就需要继承类RefBase。

arduino 复制代码
class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            incStrongRequireStrong(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                incWeakRequireWeak(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); 
    }

protected:
    // When constructing these objects, prefer using sp::make<>. Using a RefBase
    // object on the stack or with other refcount mechanisms (e.g.
    // std::shared_ptr) is inherently wrong. RefBase types have an implicit
    // ownership model and cannot be safely used with other ownership models.

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

wp是弱指针的实现类。为RefBase提供了弱引用计数,通过weakref_type指针类型的成员变量m_refs,用来维护对象的弱引用计数。

scss 复制代码
template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(nullptr), m_refs(nullptr) { }

    // if nullptr, returns nullptr
    //
    // if a weak pointer is already available, this will retrieve it,
    // otherwise, this will abort
    static inline wp<T> fromExisting(T* other);

    // for more information about this flag, see above
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
    wp(std::nullptr_t) : wp() {}
#else
    wp(T* other);  // NOLINT(implicit)
    template <typename U>
    wp(U* other);  // NOLINT(implicit)
    wp& operator=(T* other);
    template <typename U>
    wp& operator=(U* other);
#endif

    wp(const wp<T>& other);
    explicit wp(const sp<T>& other);

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

    ~wp();

    // Assignment

    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& 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_FUNCTIONAL(>, std::greater)
    COMPARE_WEAK_FUNCTIONAL(<, std::less)
    COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal)
    COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal)

    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_refs == o.m_refs;  // Implies m_ptr == o.mptr; see invariants below.
    }

    template<typename U>
    inline bool operator == (const sp<U>& o) const {
        // Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older
        // object at the same address.
        if (o == nullptr) {
          return m_ptr == nullptr;
        } else {
          return m_refs == o->getWeakRefs();  // Implies m_ptr == o.mptr.
        }
    }

    template<typename U>
    inline bool operator != (const sp<U>& o) const {
        return !(*this == o);
    }

    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        if (m_ptr == o.m_ptr) {
            return _wp_compare_<std::greater>(m_refs, o.m_refs);
        } else {
            return _wp_compare_<std::greater>(m_ptr, o.m_ptr);
        }
    }

    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        if (m_ptr == o.m_ptr) {
            return _wp_compare_<std::less>(m_refs, o.m_refs);
        } else {
            return _wp_compare_<std::less>(m_ptr, o.m_ptr);
        }
    }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
    template<typename U> inline bool operator <= (const wp<U>& 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;
};



template<typename T> template<typename U>
wp<T>::wp(const sp<U>& other)
    : m_ptr(other.m_ptr)
{
    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}

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

template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
{
    weakref_type* otherRefs(other.m_refs);
    T* otherPtr(other.m_ptr);
    if (otherPtr) otherRefs->incWeak(this);
    if (m_ptr) m_refs->decWeak(this);
    m_ptr = otherPtr;
    m_refs = otherRefs;
    return *this;
}

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

wp并不能直接操作它引用的对象,是因为wp类并没有重载*和->操作符号,因此无法对wp通过*和->进行调用。那么在需要操作它所引用的对象的时候,需要使用wp的成员函数promote,其实现如下:

arduino 复制代码
template<typename T>
// 弱指针进行升级为强指针
// promote返回sp类型就可以对其进行操作
sp<T> wp<T>::promote() const
{
    sp<T> result;
    // 实际上是通过weakref_impl的attemptIncStrong函数来检查该对象是否被释放
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        // 如果该对象有效,将m_ptr赋值到上面定义的sp类中
        result.set_pointer(m_ptr);
    }
    // 返回一个强引用,它指向的对象与该弱引用指向的对象是同一个对象
    return result;
}

3、Android中的实际使用场景

可 wp 的使用和JAVA中的回调使用一样。由于回调经常有可能生命周期比正常activity等要长,使用 wp 来引用可以减少内存泄漏可能

arduino 复制代码
class OpsCallback : public BnAppOpsCallback {
public:
    explicit OpsCallback(wp<BasicClient> client);
    virtual void opChanged(int32_t op, const String16& packageName);

private:
    wp<BasicClient> mClient;

}; // class OpsCallback

class BasicClient : public virtual RefBase {
    friend class CameraService;
    public:
        virtual status_t       initialize(sp<CameraProviderManager> manager,
                const String8& monitorTags) = 0;
        virtual binder::Status disconnect();

        // because we can't virtually inherit IInterface, which breaks
        // virtual inheritance
        virtual sp<IBinder>    asBinderWrapper() = 0;

        // Return the remote callback binder object (e.g. ICameraDeviceCallbacks)
        sp<IBinder>            getRemote() {
            return mRemoteBinder;
        }
        ...
        // these are initialized in the constructor.
        static sp<CameraService>        sCameraService;
        ...
}

其中 sp 的 CameraService 也继承了 RefBase 。

arduino 复制代码
QSSI.13/frameworks/av/services/camera/libcameraservice/CameraService.h
class CameraService :
    public BinderService<CameraService>,
    public virtual ::android::hardware::BnCameraService,
    public virtual IBinder::DeathRecipient,
    public virtual CameraProviderManager::StatusListener
{
    friend class BinderService<CameraService>;
    friend class CameraOfflineSessionClient;
public:
...
}


QSSI.13/frameworks/av/services/camera/libcameraservice/common/CameraProviderManager.h

struct StatusListener : virtual public RefBase {
        ~StatusListener() {}

        virtual void onDeviceStatusChanged(const String8 &cameraId,
                CameraDeviceStatus newStatus) = 0;
        virtual void onDeviceStatusChanged(const String8 &cameraId,
                const String8 &physicalCameraId,
                CameraDeviceStatus newStatus) = 0;
        virtual void onTorchStatusChanged(const String8 &cameraId,
                TorchModeStatus newStatus,
                SystemCameraKind kind) = 0;
        virtual void onTorchStatusChanged(const String8 &cameraId,
                TorchModeStatus newStatus) = 0;
        virtual void onNewProviderRegistered() = 0;
    };

而 LightRefBase 的使用在 CameraFlashlight 中有体现。

arduino 复制代码
class CameraFlashlight : public virtual VirtualLightRefBase {
    public:
        CameraFlashlight(sp<CameraProviderManager> providerManager,
                CameraProviderManager::StatusListener* callbacks);
        virtual ~CameraFlashlight();
    ...
}


QSSI.13/frameworks/av/services/camera/libcameraservice/CameraService.h

// flashlight control
sp<CameraFlashlight> mFlashlight;
相关推荐
醉の虾12 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧21 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm30 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep70143 分钟前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王1 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒1 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃2 小时前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰2 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter