Android智能指针初探——轻量级指针(Light Pointer)

语言: CN / TW / HK

相信有很多小伙伴跟我一样,一直从事Android上层应用开发,对Android底层充满兴趣,奈何基础知识薄弱,每次学习源码进入native层的时候,都想放弃。不用灰心,一遍看不懂就再来一遍,今天主要是分享Android智能指针的内容。

作为上层应用开发者对C++不是很熟悉,不要慌,咱们一步一步来,接下来我将分为3篇文章来讲解智能指针

1、智能指针初探——轻量级指针(Light Pointer)

2、智能指针初探——强指针(Strong Pointer)(未更新)

3、智能指针初探——弱指针(Weak Pointer)(未更新)

本篇是智能指针初探——轻量级指针(Light Pointer),在讲解智能指针之前我们先思考下为什么java没有指针。

java

做Android上层应用开发肯定离不开java,很多人选择学习java最主要的原因是没有指针,再也不用担心各种指针和内存释放了。

java //java Object a = new Object();

java在设计中尽量淡化了指针的概念,我们可以简单的new对象,上面示例代码就是java生成一个对象的最简单样例,我们可以通过变量a去使用刚刚new好的Object对象。变量a是一个对象类型或者说是引用类型,作用其实跟C/C++中的指针类似。

java中引用分为如下4类,感兴趣的同学可以自行去学习:

| 引用类型 | 概述 | | ------------------------ | ------------------------------------------------------------ | | StrongReference(强引用) | 强引用是最经常使用的一种引用,如new操作创建的对象就属于强引用,只要强引用关系还存在,垃圾收集器就不会回收掉被引用的对象。 | | SoftReferenc(软引用) | 内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存,只要垃圾回收器没有回收它,该对象就可以被程序使用。 | | WeakReferenc(弱引用) | 弱引用也是用来描述那些非必须对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只 被弱引用关联的对象 | | PhantomReference(虚引用) | 虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系。一个对象是否有虚引用的 存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚 引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。 |

这些引用类型配合Java垃圾回收机制(GC),让我们java程序员不用太关心内存的释放。Java垃圾回收机制正是由java虚拟机(JVM)提供,在Android也有对应的虚拟机:Dalvik 虚拟机(Dalvik Virtual Machine),ART(Android Runtime)虚拟机。 java在进行垃圾回收机制(GC)时,需要做两件事:

1、判断该对象是否为垃圾

2、垃圾回收的具体算法

判断该对象是否为垃圾

1、引用计数法

原理其实很简单,给运行的对象添加一个引用计数器,每当有一个地方引用它时,计数器+1;当引用失效时,计数器就-1,任何时刻计数器为0的对象,就视作不可能再被使用。这一种方式,实现简单,逻辑也清晰,大部分的情况下,它都可以达到很好的效果,尽管这样,计数器算法还是存在但是的,但是它无法解决循环引用的场景(A、B两个对象相互引用)。

微信截图_20221206192944.png

2、可达性分析法

通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。

GC Roots包含以下:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象

  2. 方法区中类静态属性引用的对象

  3. 方法区中常量引用的对象

  4. 本地方法栈中JNI(即一般说的native方法)中引用的对象

......

虽然这些虚拟机已帮忙我们回收内存,但其实我们做上层应用开发时还是得特别需要注意引用,不然还是会造成OOM等异常。

垃圾回收的具体算法

java垃圾回收的算法有很多这里就不详细展开了(标记-清除算法、 标记-整理算法、 复制算法、分代收集算法...),感兴趣的同学可以自行学习

C++

相比较java的引用+垃圾回收机制,C++没有垃圾回收的机制,通常使用引用计数的方法来统计对象的使用情况,为了实现引用计数,需要有个类来负责计数,我们先看下最简单的轻量级指针(Light Pointer)。

本文中的源代码可下面链接查看:

http://www.aospxref.com/android-7.1.2_r39/xref/system/core/include/utils/StrongPointer.h

http://www.aospxref.com/android-7.1.2_r39/xref/system/core/include/utils/RefBase.h

http://www.aospxref.com/android-7.1.2_r39/xref/system/core/libutils/RefBase.cpp

轻量级指针(Light Pointer)

我们希望指针指向的对象有引用计数功能,当计数为0时,删除对象,所以需要有个类能够实现引用计数的功能。

轻量级指针(Light Pointer)的引用计数类就是它:LightRefBase(system/core/include/utils/RefBase.h)

template <class T> class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast<const T*>(this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount; } ​ protected: inline ~LightRefBase() { } ​ private: mutable volatile int32_t mCount; };

我们简单看下这个类,重点关注mCount这个变量的使用,在incStrong中+1,在decStrong是-1(当前mCount为1时,再减就要为0了,就会delete对象)。

好了,现在我们有了引用计数类之后,还缺少一个关键角色:指针sp(system/core/include/utils/StrongPointer.h)

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

sp类是个模版类,主要的工作就是指针指向m_ptr,在构造函数、析构函数、重载函数(operator =)中控制m_ptr中的计数,而m_ptr指向的对象就是继承自LightRefBase。

//以下只截取了部分代码,详细代码内容参考 StrongPointer.h //普通构造函数 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() {     if (m_ptr)         m_ptr->decStrong(this); } //重载函数(operator =) template<typename T> sp<T>& sp<T>::operator =(const sp<T>& other) {     T* otherPtr(other.m_ptr);     if (otherPtr)         otherPtr->incStrong(this);     if (m_ptr)         m_ptr->decStrong(this);     m_ptr = otherPtr;     return *this; }

那么我们该如何使用轻量级指针(Light Pointer):

只需继承自LightRefBase结合sp即可。

微信截图_20221206194607.png

``` ​ class MyLightRefClass : public LightRefBase { public:        MyLightRefClass()       {               }

virtual ~MyLightRefClass()       {                     } };

int main(int argc, char* argv) {        MyLightRefClass lightClass = new MyLightRefClass();        sp lp = lightClass;

} ``` 轻量级指针的分享就结束了,轻量级指针很简单但是有一个问题没有解决:A、B相互引用,关于后面的强指针、弱指针还请继续关注