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

本文介绍了Android系统中智能指针的使用,特别是轻量级指针的概念。通过分析RefBase.h和StrongPointer.h,揭示了轻量级指针的实现原理,并提供了简单的使用示例,帮助理解如何在实践中应用轻量级指针。
摘要由CSDN通过智能技术生成

  • 为了能更加了解整个 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;
}
  • 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)
  • 单独编译指令:
    • 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
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值