Android的引用计数怎么实现
本篇内容主要讲解“Android的引用计数怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android的引用计数怎么实现”吧!
专注于为中小企业提供网站设计、成都网站制作服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业巴马免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了近千家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
1:问题
不像java这种runtime提供内存回收机制的语言,c c++开发中经常困扰开发者的是变量的分配与回收,当new完对象而忘记delete就会造成内存泄漏,如果delete了还在别处引用当对象,就会形成野指针
2:解决
一种内存回收策略叫引用计数,当对象被引用时,引用计数就+1,不再引用的时候引用计数就-1,当引用计数为0时,就回收对象。这种内存回收机制的问题是不能回收循环引用的对象,a对象有b对象的引用,同时b对象持有a对象的引用,就会出现a,b对象的引用数永远不可能为零的情况出现。
Android最简单的引用计数实现
templateclass 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 (this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount.load(std::memory_order_relaxed); } typedef LightRefBase 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 mCount; };
仅仅是通过± mCount的值来进行判断变量是否还有引用引用,如果引用数降为零则会调用 delete static_cast
智能指针
sp strongPointer
wp weakPointer
这两个类的共同基类是refbase.cpp
使用场景:
在framework native 代码中经常会有如下用法
spproc = ProcessState::self(); sp ProcessState::self() { Mutex::Autolock _l(gProcessMutex); if (gProcess != nullptr) { return gProcess; } gProcess = new ProcessState(kDefaultDriver); return gProcess; }
通过=操作符初始化sp
templatetemplate sp & sp ::operator =(sp&& other) { T* oldPtr(*const_cast (&m_ptr)); if (m_ptr) m_ptr->decStrong(this); if (oldPtr != *const_cast (&m_ptr)) sp_report_race(); m_ptr = other.m_ptr; other.m_ptr = nullptr; return *this; }
mptr是指向范性类型的指针 T*,T类型都是RefBase类型的派生类。如果之前有值会decStrong,并且将m_ptr指向新的RefBase类型的派生类
下面详细说下RefBase的incStrong与decStrong及WeakRef_type的incWeak与decWeak方法,整个引用计数计算方式及引用计数引起的对象构造,析构都围绕这四个方法展开。
特别关注
RefBase引用类型定义
enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 };
及weakRef_impl类的四个成员变量
std::atomicmStrong; //线程原子操作变量 std::atomic mWeak; //线程原子操作变量 RefBase* const mBase; std::atomic mFlags; //线程原子操作变量 explicit weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { }
incWeak
void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast(this); impl->addWeakRef(id); //非debug模式什么也不做 const int32_t c __unused = impl->mWeak.fetch_add(1, std::memory_order_relaxed); //impl变量mWeak线程安全模式+1 ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); }
incStrong
void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); //若引用计数 refs->addStrongRef(id); const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);// mStrong成员变量+1 if (c != INITIAL_STRONG_VALUE) { //如果不是第一次强引用计数+1则直接返回 return; } //如果是第一次则会把mStrong的初始值减去也就是使它的值 从1开始计算 int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed); ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old); refs->mBase->onFirstRef(); //第一次会回调onFirstRef }
decWeak
void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast(this); impl->removeWeakRef(id); const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release); //mWeak变量值线程安全-1 if (c != 1) return; //如果引用计数值>1及不止一个sp引用到这个变量,则return //如果这是最后一个引用 atomic_thread_fence(std::memory_order_acquire); int32_t flags = impl->mFlags.load(std::memory_order_relaxed); if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { // This is the regular lifetime case. The object is destroyed // when the last strong reference goes away. Since weakref_impl // outlives the object, it is not destroyed in the dtor, and // we'll have to do it here. if (impl->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {//如果mstrong是初始值,也就是没有执行过incStrong // Decrementing a weak count to zero when object never had a strong // reference. We assume it acquired a weak reference early, e.g. // in the constructor, and will eventually be properly destroyed, // usually via incrementing and decrementing the strong count. // Thus we no longer do anything here. We log this case, since it // seems to be extremely rare, and should not normally occur. We // used to deallocate mBase here, so this may now indicate a leak. ALOGW("RefBase: Object at %p lost last weak reference " "before it had a strong reference", impl->mBase); } else { delete impl; } } else { // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference // is gone, we can destroy the object. //如果是弱引用并且是最后一个引用则会回调 onLastWeakRef方法 impl->mBase->onLastWeakRef(id); delete impl->mBase; //析构对象本身 } }
析构函数
RefBase::~RefBase() { int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed); // Life-time of this object is extended to WEAK, in // which case weakref_impl doesn't out-live the object and we // can free it now. if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { // It's possible that the weak count is not 0 if the object // re-acquired a weak reference in its destructor //如果是弱引用并且引用计数是0 if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) { delete mRefs; //析构impl类 } } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) { // We never acquired a strong reference on this object. LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0, "RefBase: Explicit destruction with non-zero weak " "reference count"); // TODO: Always report if we get here. Currently MediaMetadataRetriever // C++ objects are inconsistently managed and sometimes get here. // There may be other cases, but we believe they should all be fixed. delete mRefs; } // For debugging purposes, clear mRefs. Ineffective against outstanding wp's. const_cast(mRefs) = nullptr; }
到此,相信大家对“Android的引用计数怎么实现”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
新闻标题:Android的引用计数怎么实现
网址分享:http://cdiso.cn/article/jhesge.html