Android 智能指针学习笔记(一) —— 简述以及轻量级指针

来源:互联网 发布:java web 工作流引擎 编辑:程序博客网 时间:2024/06/10 09:01

  • NOTE
  • 为何用智能指针
  • 智能指针背景
  • Android 智能指针分类
  • 轻量级指针
    • 轻量级指针实现原理
      • 1 RefBaseh
      • 2 StrongPointerh
    • 轻量级指针的使用

  • 为了能更加了解整个 Android 系统的运作,我买了老罗出版的,源码分析的书,打算在业务比较空闲的时间里慢慢学习……
  • 由于在源码中经常能看到智能指针的应用,于是趁着这两天没有项目,我就把智能指针的这一章啃了一遍。

NOTE

  • 参考源码版本:Android 7.1.2。
  • 以下代码追踪思路均参考《Android 系统源代码情景分析(修订版)》

为何用智能指针

  • Android 系统源码中,含有大量的 c++ 代码,既然用到了 c++ ,就无法避免使用指针。
  • c++ 指针若使用不当,轻则内存泄露,重则导致难以发现的逻辑错误,甚至系统崩溃。
  • 为了尽可能避免错误地使用 c++ 指针,Android 系统为我们提供了 c++ 智能指针。

智能指针背景

  • 我们通常通过引用计数技术来维护对象的生命周期。
  • 人为手动维护计数风险很大,必须采用一种自动的引用计数维护技术。
  • 智能指针:
    • 它是一个对象,而非指针。但它引用了一个实际使用的对象。
    • 通过在构造函数中加入引用计数来实现自动计数维护。
    • 这样的简单计数无法解决相互引用的对象释放问题。
  • 为了解决相互引用而引发的问题,前人提出了 “强引用” 与 “弱引用” 的概念。
  • AB 的例子:
    • 条件: A 强引用 BB 弱引用 A
    • A 的生命周期不受 B 的影响,故 A 可以安全地释放空间。
    • 在释放 A 时,同时也会释放它对 B 的强引用计数,此时 B 也就可以安全地释放空间了。
    • 对象的生命周期不受弱引用计数控制:
      • 情景:B 想要使用 A,此时 A 已经释放。
      • B 若想使用对象 A,则需要先将弱引用升级为强引用。
      • 由于 A 已经释放,所以这个弱引用无法升级。
      • 弱引用无法升级,则可判断 B 已经无法再使用 A

Android 智能指针分类

  • 轻量级指针:Light Pointer
  • 强指针:Strong Pointer
  • 弱指针:Weak Pointer

轻量级指针

1. 轻量级指针实现原理

1.1 RefBase.h

  • 位置:system/core/include/utils/RefBase.h
  • LightRefBase 的实现:
    • 模板类:T 表示实际类型,它必须继承 LightRefBase前提是它只需要用到轻量指针)。
    • 只有一个成员变量 mCount 用于描述引用计数值。
    • 提供 incStrongdecStrong 来增加、减少引用计数。
    • 注意一些新增的东西:
      • __attribute__((unused)):该函数或变量可能不使用,可避免编译器警告。
      • atomic:保证关于它的操作是原子性的
      • 友元类 ReferenceMover
      • static 函数 renameRef():空函数
      • static 函数 renameRefId():空函数
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;};

1.2 StrongPointer.h

  • 轻量级指针实现类 sp
    • 它同时也是强指针的实现类。
    • 模板类:T 必须继承 LightRefBase
    • 与轻量级指针相关的部分:
      • m_ptr:指向了引用的实际对象。
      • 构造函数:增加计数。
      • 析构函数:减少计数。
template<typename T>class sp {public:    inline sp() : m_ptr(0) { }    sp(T* other);    sp(const sp<T>& other);    sp(sp<T>&& other);    template<typename U> sp(U* other);    template<typename U> sp(const sp<U>& other);    template<typename U> sp(sp<U>&& other);    ~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;};
  • 构造函数与析构函数:
    • 由于 m_ptr 指向的对象继承了 LightRefBase,所以这里实际上是通过调用 LightRefBase 类的 incStrongdecStrong 来改变计数的。
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);}template<typename T>sp<T>::sp(sp<T>&& other)        : m_ptr(other.m_ptr) {    other.m_ptr = nullptr;}template<typename T>sp<T>::~sp() {    if (m_ptr)        m_ptr->decStrong(this);}

2. 轻量级指针的使用

  • 轻量级指针比较简单,与它相关的就只有这一点内容。
  • 为了巩固对轻量级指针的理解,我照着老罗给的例子写了实践的代码,在模拟器上跑了下面这个小程序。
  • 在源码目录下的 external/ 中创建一个文件夹 lightpointer
  • 相关文件:
    • external/lightpointer/Android.mk
    • external/lightpointer/lightpointer.cpp
  • lightpointer.cpp 实现:
#include <stdio.h>#include <utils/RefBase.h>using namespace android;class LightClass : public LightRefBase<LightClass>{public :        LightClass()        {            printf("Construct LightClass Object.\n");        }        virtual ~LightClass()        {            printf("Destroy LightClass Object.\n");        }};int main(int argc, char** argv){    LightClass* pLightClass = new LightClass();    sp<LightClass> lpOut;    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;}
  • Andoird.mk 实现:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_MODULE := lightpointerLOCAL_SRC_FILES := lightpointer.cppLOCAL_SHARED_LIBRARIES := \            libcutils \            libutilsinclude $(BUILD_EXECUTABLE)
  • 单独编译指令:
    • mmm ./external/lightpointer/
    • make snod
  • 编译成功后,用 adb shell 进入 system/bin,运行 lightpointer

    • 结果如下。

    Construct LightClass Object.
    Light Ref count : 1.
    Light Ref count : 2.
    Light Ref count : 1.
    Destroy LightClass Object.

  • 分析输出:

    • 开始时,我们创建了一个 LightClass 实例 pLightClass
    • 注意,这个 LightClass 继承了 LightRefBase
    • 创建一个轻量级指针 lpOut 指向 pLightClass,此时计数器 +1,计数值为 1
    • 再次创建轻量级指针 lpInner 指向 lpOut,此时 pLightClass 的计数 +1,计数值为 2
    • 注意到 lpInner 的生命周期在第二次输出计数值后就结束了,此时计数 -1,计数值为 1
  • 阅读全文
    0 0