Android Q智能指针sp,wp

概述

java提供了垃圾回收机制,不需要程序员自己手动释放对象,c++对于堆上创建的对象需要手动delete,对于庞大的Android系统来说,对象实在容易因为各种原因被忘记释放,造成内存泄露,所以Android提供了一种智能指针来帮助对象释放,sp强指针,wp弱指针。

主要的类

智能指针主要涉及如下几个类:

/system/core/libutils/RefBase.cpp
/system/core/include/utils/RefBase.h
/system/core/libutils/include/utils/StrongPointer.h

Android native层有大量的sp类型对象,想要具有自动释放对象的类必须继承RefBase基类,看一下RefBase.h定义了哪些方法

RefBase.h

RefBase主要提供了增加强引用和减少强引用,还有个内部类,这个内部类才是主要管理对象引用计数的核心

class RefBase
  {
  public:
              void            incStrong(const void* id) const;
              void            decStrong(const void* id) const;
              void            forceIncStrong(const void* id) const;
              int32_t         getStrongCount() const;
  
      class weakref_type
      {
      public:
          RefBase*            refBase() const;
          void                incWeak(const void* id);
          void                decWeak(const void* id);
          bool                attemptIncStrong(const void* id);
          bool                attemptIncWeak(const void* id);
          int32_t             getWeakCount() const;
  
      };

RefBase.cpp

先看构造函数,构造函数中创建了weakref_impl,这是weakref_type具体实现类,用来管理对象的引用计数

 RefBase::RefBase()
      : mRefs(new weakref_impl(this))
  {
  }

RefBase析构

RefBase::~RefBase()
  {
       //获取mFlags的值
      int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
      //如果是弱引用控制
      if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
          //如果弱引用等于0
          if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
              //删除对象的weakref_impl
              delete mRefs;
          }
          //如果没有增加强引用,mStrong初始化时为INITIAL_STRONG_VALUE
      } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
         //什么都不做
      }
      //最终将weakref_impl置为空
      const_cast<weakref_impl*&>(mRefs) = nullptr;
  }

atomic是模板类,对一系列数据进行原子操作,这里mStrong,mWeak,mFlags都是int类型的

class RefBase::weakref_impl : public RefBase::weakref_type
  {
  public:
      std::atomic<int32_t>    mStrong;
      std::atomic<int32_t>    mWeak;
      RefBase* const          mBase;
      std::atomic<int32_t>    mFlags;
  
  //注意,这里面的方法是debug版本才会有的,正式版本不用关注
  #if !DEBUG_REFS
  
      explicit weakref_impl(RefBase* base)
          : mStrong(INITIAL_STRONG_VALUE)
          , mWeak(0)
          , mBase(base)
          , mFlags(0)
      {
      }
  
      void addStrongRef(const void* /*id*/) { }
      void removeStrongRef(const void* /*id*/) { }
      void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
      void addWeakRef(const void* /*id*/) { }
      void removeWeakRef(const void* /*id*/) { }
      void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
      void printRefs() const { }
      void trackMe(bool, bool) { }
  
  #else
  
      weakref_impl(RefBase* base)
           //#define INITIAL_STRONG_VALUE (1<<28)
           //给强引用初始化值为1<<28
          : mStrong(INITIAL_STRONG_VALUE)
          //弱引用为0
          , mWeak(0)
          //base指向创建智能指针的具体对象
          , mBase(base)
          //mFlags为0,
          , mFlags(0)
          , mStrongRefs(NULL)
          , mWeakRefs(NULL)
         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
          , mRetain(false)
      {
      }

说一下mFlages,有三个类型,
OBJECT_LIFETIME_STRONG:强引用控制,当强引用计数为0,不管弱引用计数为多少都会释放对象。
OBJECT_LIFETIME_WEAK:弱引用控制,当强引用和弱引用为0才会释放对象。
OBJECT_LIFETIME_MASK:需要手动释放对象。
默认值为OBJECT_LIFETIME_STRONG,可以通过extendObjectLifetime进行修改。

enum {
          OBJECT_LIFETIME_STRONG  = 0x0000,
          OBJECT_LIFETIME_WEAK    = 0x0001,
          OBJECT_LIFETIME_MASK    = 0x0001
      };

StrongPointer.h

sp构造对象的四种方式,两种括号两种等于号

//方式1
template<typename T>
  sp<T>::sp(T* other)
          : m_ptr(other) {
      if (other)
          other->incStrong(this);
  }
 //方式2
template<typename T>
  sp<T>::sp(const sp<T>& other)
          : m_ptr(other.m_ptr) {
      if (m_ptr)
          m_ptr->incStrong(this);
  }
  //方式3
 template<typename T>
  sp<T>& sp<T>::operator =(const sp<T>& other) {
      // Force m_ptr to be read twice, to heuristically check for data races.
      T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
      T* otherPtr(other.m_ptr);
      if (otherPtr) otherPtr->incStrong(this);
      if (oldPtr) oldPtr->decStrong(this);
      if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
      m_ptr = otherPtr;
      return *this;
  }
//方式4
template<typename T>
  sp<T>& sp<T>::operator =(T* other) {
      T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
      if (other) other->incStrong(this);
      if (oldPtr) oldPtr->decStrong(this);
      if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
      m_ptr = other;
      return *this;
  }

祁构函数:

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

在Android源码中创建强指针往往会以下面的形式:

//方式2
sp<ProcessState> proc(ProcessState::self());
//方式4
sp<ProcessState> proc = new ProcessState();

方式2

 //方式2
template<typename T>
  sp<T>::sp(const sp<T>& other)
          //m_ptr指向具体的引用对象
          : m_ptr(other.m_ptr) {
      if (m_ptr)
          m_ptr->incStrong(this);
  }

当m_ptr不为0则会调用对象的incStrong方法增加强引用计数1

incStrong

增加强引用计数

void RefBase::incStrong(const void* id) const
  {
      //在初始化具体的强引用对象时在Refbase构造函数中
      //创建weakref_impl,赋值为mRefs
      weakref_impl* const refs = mRefs;
      //弱引用计数加1
      refs->incWeak(id);
      //前面说过,debug版本实现,正是版本为空
      refs->addStrongRef(id);
      //c++11的API,原子+1操作,返回+1之前的值
      const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
      //在初始化具体对象时mStrong赋初值为INITIAL_STRONG_VALUE
      //如果c在+1之前不为INITIAL_STRONG_VALUE,说明不是第一次增加强引用
      //直接return,不执行后面操作
      if (c != INITIAL_STRONG_VALUE)  {
          return;
      }
      //c++11的API,mStrong执行减INITIAL_STRONG_VALUE的操作
      //相当于mStrong = INITIAL_STRONG_VALUE+1-INITIAL_STRONG_VALUE = 1
      int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
      //第一次增加强引用时调用onFirstRef方法
      refs->mBase->onFirstRef();
  }

incWeak

增加弱引用计数,这个方法很简单,弱引用计数加一

void RefBase::weakref_type::incWeak(const void* id)
  {
      weakref_impl* const impl = static_cast<weakref_impl*>(this);
      impl->addWeakRef(id);//debug版本方法
      //c++11 API,原子操作+1
      const int32_t c __unused = impl->mWeak.fetch_add(1,
              std::memory_order_relaxed);
      ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
  }

可以看到incStrong主要做的事为强引用加1,弱引用加1,并且如果是首次增加强引用时调用对象的onFirstRef方法

sp的几种初始化方法中无非都是调用了incStrong和decStrong,在使用sp的=重载操作符时都会调用前一个对象的decStrong函数减少强引用(如果有之前的对象的话)。

decStrong

void RefBase::decStrong(const void* id) const
  {
      weakref_impl* const refs = mRefs;
      refs->removeStrongRef(id); //debug版本实现
      //c++11 API,mStrong原子操作-1
      const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
      //如果减1之前等于1,说明此时强引用为0
      if (c == 1) {
          //线程同步
          std::atomic_thread_fence(std::memory_order_acquire);
          //调用具体对象如ProcessState的onLastStrongRef方法
          refs->mBase->onLastStrongRef(id);
          //c++11 API,获取mFlags的值
          int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
          //当mFlags为强引用控制时,默认为强引用控制
          if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {             //直接释放对象
              delete this;
            }
      //无论如何都会减少弱引用计数
      refs->decWeak(id);
  }

decWeak

void RefBase::weakref_type::decWeak(const void* id)
  {
      weakref_impl* const impl = static_cast<weakref_impl*>(this);
      impl->removeWeakRef(id);//debug版本实现,release为空
      //c++11 API,弱引用减1
      const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
      //当弱引用减1之前为不为1,说明弱引用减1之后还不会为0
      //则return,不执行后面代码,仅仅弱引用减1就行了
      if (c != 1) return;
      //线程同步
      atomic_thread_fence(std::memory_order_acquire);
      //获取mFlags的值
      int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
      //当mFlags为强引用控制
      if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
         //获取mStrong的值,如果等于INITIAL_STRONG_VALUE,说明
         //此对象没有添加强引用,因为mStrong的初始值就是INITIAL_STRONG_VALUE
          if (impl->mStrong.load(std::memory_order_relaxed)
                  == INITIAL_STRONG_VALUE) { 
                  //什么都不做,这里在Android O之后修改过,之前是会释放对象的
                  //delete impl->mBase;
          } else {
              //添加过强引用则释放weakref_impl对象
              delete impl;
          }
      } else {
          //当mFlags为弱引用控制时,调用对象onLastWeakRef方法
          impl->mBase->onLastWeakRef(id);
          //释放对象
          delete impl->mBase;
      }
  }

decStrong主要做的事就是强引用减1,弱引用减1,
当强引用为0并且mFlags为强引用控制时释放对象,
decWeak中会对弱引用减为0之后做一些判断,当mFlags为强引用控制并且对象没有添加过强引用则什么都不做,当mFlags为强引用控制并且对象有添加过强引用则释放weakref_impl,当mFlags为弱引用控制则调用对象onLastWeakRef方法并且释放对象

理解sp主要需要理解这几个增加减少强弱引用的方法,sp创建时强弱引用+1,sp析构的时候强弱引用-1,在根据mFlags来决定当强弱引用为0时是否释放对象,
mFlags为强引用控制时只要强引用为0则释放对象,当mFlags为弱引用控制时,只有强弱引用都为0才释放对象。

wp

wp初始化方法的几种方式中都是调用的几个方法decWeak,incWeak,createWeak,前面两个已经分析过

template<typename T>
  wp<T>::wp(T* other)
      : m_ptr(other)
  {
      m_refs = other ? m_refs = other->createWeak(this) : nullptr;
  }
  
  template<typename T>
  wp<T>::wp(const wp<T>& other)
      : m_ptr(other.m_ptr), m_refs(other.m_refs)
  {
      if (m_ptr) m_refs->incWeak(this);
  }
  
  template<typename T>
  wp<T>& wp<T>::operator = (T* other)
  {
      weakref_type* newRefs =
          other ? other->createWeak(this) : nullptr;
      if (m_ptr) m_refs->decWeak(this);
      m_ptr = other;
      m_refs = newRefs;
      return *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;
  }

createWeak

这个方法里面调用incWeak,弱引用+1

RefBase::weakref_type* RefBase::createWeak(const void* id) const
  {
      mRefs->incWeak(id);
      return mRefs;
  }

wp析构函数

也很简单,弱引用-1,之前分析过了

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

其实Android智能指针对对象内存管理核心就是这几个方法,增加强引用(incStrong),减少强引用(decStrong),增加弱引用(incWeak),减少弱引用(decWeak)。

当对象创建为sp强指针时在sp的构造函数中调用对象的incStrong,incStrong中调用incWeak,最终结果强引用+1,弱引用+1,在出了sp作用域之后调用sp的析构函数,析构函数中调用对象的decStrong,decStrong中调用decWeak,最终结果强引用-1,弱引用-1,然后会根据mFlags判断以何种方式释放对象,再来回顾一下mFlags的值:

enum {
          //强引用控制:当强引用为0就释放对象,不管弱引用
          OBJECT_LIFETIME_STRONG  = 0x0000,
          //弱引用控制:当强弱引用都为0才释放对象
          OBJECT_LIFETIME_WEAK    = 0x0001,
          //不主动释放对象,需要手动释放
          OBJECT_LIFETIME_MASK    = 0x0001
      };

弱指针wp的存在意义有是什么呢?

按理说我们要管理c++内存对象有一个强指针sp就行了,为何还需要弱指针wp,先看一段代码:

class Student : public RefBase {
  public:
    Student() {
        printf("Construct Student......");
    }
    ~Student() {
        printf("Destory Student......");
    }
    void setTeacher(sp<Teacher> teacher) { mTeacher = teacher; }
  
  private:
    sp<Teacher> mTeacher;
};
class Teacher : public RefBase {
  public:
    Teacher() {
        printf("Construct Teacher......");
    }
     ~Teacher() {
        printf("Destory Teacher......");
    }
    void setStudent(sp<Student> student) { mStudent = student; }
  
  private:
    sp<Student> mStudent;
};

int main(int argc, char** argv)
{
    Student* student = new Student();
    Teacher* teacher = new Teacher();
    {
        sp<Student> student_sp = student;
        sp<Teacher> teacher_sp = teacher;

        teacher->setStudent(student);
        student->setTeacher(teacher);
      
    }
    return 0;
}

创建了两个类Student和Teacher,都继承自RefBase,具有对象内存管理功能,首先分别对两个类创建sp,此时Student和Teacher的强弱引用分别+1,接着分别调用对方的set方法,Set方法里又创建sp,Student和Teacher的强弱引用再+1,Student和Teacher相互持有对方强引用,此时Student和Teacher的强弱引用都为2,当大括号作用域结束之后,调用sp析构函数,前面分析了sp析构函数中会将强弱引用-1,但是此时Student和Teacher还相互引用着,所以sp强弱引用都不为0,导致这两个对象无法释放。

修改一下代码:将Student持有Teacher的引用改为弱引用,

class Student : public RefBase {
  public:
    Student() {
        printf("Construct Student......");
    }
    ~Student() {
        printf("Destory Student......");
    }
    void setTeacher(wp<Teacher> teacher) { mTeacher = teacher; }
  
  private:
    wp<Teacher> mTeacher;
};
class Teacher : public RefBase {
  public:
    Teacher() {
        printf("Construct Teacher......");
    }
     ~Teacher() {
        printf("Destory Teacher......");
    }
    void setStudent(sp<Student> student) { mStudent = student; }
  
  private:
    sp<Teacher> mStudent;
};
int main(int argc, char** argv)
{
    Student* student = new Student();
    Teacher* teacher = new Teacher();
    {
        sp<Student> student_sp = student;
        sp<Teacher> teacher_sp = teacher;

        teacher->setStudent(student);
        student->setTeacher(teacher);
      
    }
    return 0;
}

构造Student的sp,Student的强弱引用+1,构造Teacher的sp,Teacher的强弱引用+1,继续相互调用set方法,Teacher持有Student的强引用,Student的强弱引用+1,Student持有Teacher弱引用,Teacher的弱引用+1,此时Student的强弱引用为2,Teacher的强引用为1,弱引用为2,sp大括号结束,sp释放,调用incStrong,Student和Teacher的强弱引用-1,此时Teacher的强引用为0,弱引用为1,由于mFlags默认为:所以此时Teacher释放,Teacher释放后不再持有Student的强引用,Student强引用减为0,最终Student也得到释放。

	//强引用控制:当强引用为0就释放对象,不管弱引用
    OBJECT_LIFETIME_STRONG  = 0x0000,

总结:wp可以用来解决对象相互引用的问题。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值