Android 智能指针详解 -- RefBase
来源:互联网 发布:java web统计登录次数 编辑:程序博客网 时间:2024/05/03 12:51
来源:
http://blog.csdn.net/shift_wwx/article/details/78864099
前言:
关于android 智能指针,前面详细分析了sp 和 wp的source code,但是还有一些疑问,在这一篇中全部解释,因为所有的源头都是来自于这里。
更多信息可以看 sp的博文 和 wp的博文
本文总结基于Android 7.0
source code:
system/core/include/utils/RefBase.h
system/core/include/libutils/RefBase.cpp
可能最开始有人注意到,sp 和 wp都是模板类,模板参数是T 或者是U,构造函数或者重载运算符的函数中形参看到的是T * 、 U *,或者是sp<T> &、wp<T> &,完全没有看出来跟RefBase 有什么关系。但是,看完Android 中使用sp 和 wp的地方就知道,传进来的模板参数都是继承自RefBase,所谓的指针类型都是基于这个类。
例如:
class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier{public: MediaPlayer(); ~MediaPlayer(); void died(); void disconnect();父类是BnMediaPlayerClient 和 IMediaDeathNotifier,
class IMediaDeathNotifier: virtual public RefBase{public: IMediaDeathNotifier() { addObitRecipient(this); } virtual ~IMediaDeathNotifier() { removeObitRecipient(this); }随便找个,可以看到是继承RefBase,注意的是虚拟继承。
注意,有可能后面会有很多类继承自RefBase,为了避免继承二义性,RefBase 的派生类都必须要虚拟继承。
来看下RefBase定义的地方:
class RefBase{public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; //! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const; class weakref_type { public: RefBase* refBase() const; void incWeak(const void* id); void decWeak(const void* id); // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. bool attemptIncWeak(const void* id); //! DEBUGGING ONLY: Get current weak ref count. int32_t getWeakCount() const; //! DEBUGGING ONLY: Print references held on object. void printRefs() const; //! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; //! DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); } //! DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype;protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id);private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o);private: friend class ReferenceMover; static void renameRefs(size_t n, const ReferenceRenamer& renamer); static void renameRefId(weakref_type* ref, const void* old_id, const void* new_id); static void renameRefId(RefBase* ref, const void* old_id, const void* new_id); weakref_impl* const mRefs;};1、在sp 中看到的指针m_ptr都是通过incStrong 和decStrong 来控制计数,最终调用的就是这里的
2、在wp 中的m_refs的类型是weakref_type类型的指针,在这里也能看到了
所以对于wp中的指针来说,确切的说是RefBase类型的指针,只能调用createWeak,而incWeak和decWeak是weakref_type的对象才能调用。
这就解释了 wp博文 中遗留问题的第 1 、2
3、RefBase的关键是mRefs,类型为weakref_impl *,这个是整个智能指针的关键
下面来详细看下RefBase的实现,首先来看下RefBase的构造函数:
RefBase::RefBase() : mRefs(new weakref_impl(this)){}只有一个默认的构造函数,就是为了初始化mRefs,也就是说,以后RefBase的派生类在构造的时候,都会有个mRefs的指针变量。
来看下核心变量mRefs的类型weakref_impl:
class RefBase::weakref_impl : public RefBase::weakref_type{public: std::atomic<int32_t> mStrong; //对于强引用计数控制是通过这个变量 std::atomic<int32_t> mWeak; //对于弱引用的计数控制是通过这个变量 RefBase* const mBase; //当前指针的标志,以后可能有很多对该指针引用,但是这个mBase只有一个 std::atomic<int32_t> mFlags; //判断是强引用还是弱引用#if !DEBUG_REFS 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) //构造函数 : mStrong(INITIAL_STRONG_VALUE) //默认强引用计数为1<<28 , mWeak(0) //默认弱引用的计数为0 , mBase(base) //RefBase,也就是后来的指针,注意,后来weakref_impl需要delete的时候,这里mBase 也需要delete,具体看decWeak , mFlags(0) , mStrongRefs(NULL) //所有的强引用,用链表存储在这里 , mWeakRefs(NULL) //所有的弱引用,用链表存储 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { } ~weakref_impl() { bool dumpStack = false; if (!mRetain && mStrongRefs != NULL) { dumpStack = true; ALOGE("Strong references remain:"); ref_entry* refs = mStrongRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);#if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.log(LOG_TAG);#endif refs = refs->next; } } if (!mRetain && mWeakRefs != NULL) { dumpStack = true; ALOGE("Weak references remain!"); ref_entry* refs = mWeakRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);#if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.log(LOG_TAG);#endif refs = refs->next; } } if (dumpStack) { ALOGE("above errors at:"); CallStack stack(LOG_TAG); } } void addStrongRef(const void* id) { //强引用的指针地址会做为id存放在mStrongRefs链表中 //ALOGD_IF(mTrackEnabled, // "addStrongRef: RefBase=%p, id=%p", mBase, id); addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed)); } void removeStrongRef(const void* id) { //ALOGD_IF(mTrackEnabled, // "removeStrongRef: RefBase=%p, id=%p", mBase, id); if (!mRetain) { removeRef(&mStrongRefs, id); } else { addRef(&mStrongRefs, id, -mStrong.load(std::memory_order_relaxed)); } } void renameStrongRefId(const void* old_id, const void* new_id) { //ALOGD_IF(mTrackEnabled, // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p", // mBase, old_id, new_id); renameRefsId(mStrongRefs, old_id, new_id); } void addWeakRef(const void* id) { //将弱引用的指针作为id存放链表mWeakRefs中 addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed)); } void removeWeakRef(const void* id) { if (!mRetain) { removeRef(&mWeakRefs, id); } else { addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed)); } } void renameWeakRefId(const void* old_id, const void* new_id) { renameRefsId(mWeakRefs, old_id, new_id); } void trackMe(bool track, bool retain) { mTrackEnabled = track; mRetain = retain; } void printRefs() const //打印该指针的所有引用 { String8 text; { Mutex::Autolock _l(mMutex); char buf[128]; sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); printRefsLocked(&text, mStrongRefs); sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); printRefsLocked(&text, mWeakRefs); } { char name[100]; snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this); int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644); if (rc >= 0) { write(rc, text.string(), text.length()); close(rc); ALOGD("STACK TRACE for %p saved in %s", this, name); } else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this, name, strerror(errno)); } }private: struct ref_entry //链表结构体,单项链表 { ref_entry* next; const void* id;#if DEBUG_REFS_CALLSTACK_ENABLED CallStack stack;#endif int32_t ref; }; void addRef(ref_entry** refs, const void* id, int32_t mRef) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the // update. Positive value means we increment, negative--we // decrement the reference count. ref->ref = mRef; ref->id = id;#if DEBUG_REFS_CALLSTACK_ENABLED ref->stack.update(2);#endif ref->next = *refs; //链表前插 *refs = ref; } } void removeRef(ref_entry** refs, const void* id) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* const head = *refs; ref_entry* ref = head; while (ref != NULL) { if (ref->id == id) { *refs = ref->next; delete ref; return; } refs = &ref->next; ref = *refs; } ALOGE("RefBase: removing id %p on RefBase %p" "(weakref_type %p) that doesn't exist!", id, mBase, this); ref = head; while (ref) { char inc = ref->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); ref = ref->next; } CallStack stack(LOG_TAG); } } void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* ref = r; while (ref != NULL) { if (ref->id == old_id) { ref->id = new_id; } ref = ref->next; } } } void printRefsLocked(String8* out, const ref_entry* refs) const { char buf[128]; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; sprintf(buf, "\t%c ID %p (ref %d):\n", inc, refs->id, refs->ref); out->append(buf);#if DEBUG_REFS_CALLSTACK_ENABLED out->append(refs->stack.toString("\t\t"));#else out->append("\t\t(call stacks disabled)");#endif refs = refs->next; } } mutable Mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; bool mTrackEnabled; // Collect stack traces on addref and removeref, instead of deleting the stack references // on removeref that match the address ones. bool mRetain;#endif};
再来看下incWeak():
void RefBase::weakref_type::incWeak(const void* id){ weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->addWeakRef(id);//添加弱引用到链表中 const int32_t c __unused = impl->mWeak.fetch_add(1, std::memory_order_relaxed); //计数加1 ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);}其中addWeakRef():
void addWeakRef(const void* id) { addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed)); }添加弱引用到链表。
再来看下decWeak():
void RefBase::weakref_type::decWeak(const void* id){ weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); //删除弱引用 const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release); //计数减1 ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) 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 // outlive 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) { // Special case: we never had a strong reference, so we need to // destroy the object now. delete impl->mBase; //如果没有其他的引用了,需要释放当前指针 } else { // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference // is gone, we can destroy the object. impl->mBase->onLastWeakRef(id); delete impl->mBase; //如果没有其他引用了,就释放当前指针 }}
再来看下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); ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);#if PRINT_REFS ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);#endif if (c != INITIAL_STRONG_VALUE) { //如果不是第一次添加就返回 return; } int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed); // A decStrong() must still happen after us. ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old); refs->mBase->onFirstRef(); //第一次添加需要调用onFirstRef()}
void RefBase::decStrong(const void* id) const{ weakref_impl* const refs = mRefs; refs->removeStrongRef(id);//移除强引用链表中的引用id const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);//计数减1#if PRINT_REFS ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);#endif ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); if (c == 1) {//如果是最后一个了,那需要释放该指针了 std::atomic_thread_fence(std::memory_order_acquire); refs->mBase->onLastStrongRef(id); int32_t flags = refs->mFlags.load(std::memory_order_relaxed); if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { delete this; // Since mStrong had been incremented, the destructor did not // delete refs. } } // Note that even with only strong reference operations, the thread // deallocating this may not be the same as the thread deallocating refs. // That's OK: all accesses to this happen before its deletion here, // and all accesses to refs happen before its deletion in the final decWeak. // The destructor can safely access mRefs because either it's deleting // mRefs itself, or it's running entirely before the final mWeak decrement. refs->decWeak(id);//如果不是最后一个,需要减少弱引用链表}
这样, wp博文中的第2、4点就解释完了。
小结一下:
1、incStrong和incWeak方法比较简单,就是增加一下强引用和弱引用计数,需要注意的是,incStrong方法中会调用incWeak方法
2、decWeak方法有点复杂,要做的事有两件:是否要释放真实对象,是否要释放影子对象:
1) 如果生命周期是弱引用来控制,那么在这里就需要做判断,弱应用的计数是否为0,是否要释放真实对象和影子对象
2) 如果生命周期是强引用来控制的,那么这里也要判断一下,如果强引用计数为0的话,需要释放真实对象,弱引用计数是否为0,是否要释放影子对象
从这里我们可以看到:
弱引用计数是关系影子对象的,如果弱引用计数为0,那么影子对象一定要释放,但是真实对象不一定要释放
强引用计数是关系真实对象的,如果强引用计数为0,那么真实对象一定要释放的,但是影子对象不一定释放
3、decStrong方法主要做:就是看看是否要释放真实对象,因为强引用和真实对象关联的
4、RefBase的析构方法:真实对象被销毁的时候,需要做一个工作就是释放影子对象
释放影子对象有两个场景:
1) 如果强引用计数根本没有被使用过,那么直接释放
2) 如果强引用计数使用过,但是采用的是非强生命周期管理方式,也是释放
通过RefBase的执行过程,结合wp的构造来看,最终wp中维护的m_ptr并没有使用的地方,而整个过程都是在维护弱引用的链表。
所以,wp如果要使用必须要通过promote函数,转换成sp,再通过sp的重载运算符* 和 运算符 ->来调用指针的成员。
这也就是解释了wp博文中的第 3 点。
android中除了RefBase,还有个轻量级的引用LightRefBase,前面看到的是很多类继承RefBase,后面通过sp、wp实现了只能指针。
如果只是想通过计数方式使用只能指针,也可以用LightRefBase。
先来看下LightRefBase的定义:
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;};从整个定义来看,就一个核心变量mCount,为什么这里有incStrong、decStrong,就是为了后面使用sp准备。
可以看个例子:
class MyClass : virtual public LightRefBase<MyClass> {public: void test();};在main中使用的时候需要通过sp使用:
sp<MyClass> sp(new MyClass());sp->test();
1、LightRefBase 同RefBase一样,必须是某个指针的基类
2、LightRefBase 轻量级引用,采用的是模板机制,而不是复杂的OOP,不需要虚拟继承3、轻量级引用基类轻在内存,只拥有一个成员变量,用以计数。其引用计数类模板不含有虚函数,如果尾端类(不被其他类继承的类)直接继承引用计数基类,那尾端类也不需要虚的析构函数,不会出现因部分删除而产生内存泄露,因为模板类代码中有一处使用static_cast向下转型,模板确保其安全。
4、RefBase持有弱引用,持有指针,在进行删除工作时较为复杂。
缺陷:
1、不支持弱引用。
2、轻量级引用类,使用模版技术,所以模版技术的缺陷,轻量级引用亦有,很明显一点就是你会需要很多不同轻量级引用类。
3、编译级别支持引用栈对象,运行时会崩溃,Scott Meyers说过只要编译器允许,就一定有人这么干。此问题需要使用者解决-----利用protected dector 和 friend class refbase
到此,android中只能指针部分就告一段落,后期会在碰到问题继续补充说明。也请大神不吝赐教。
参考:
http://blog.csdn.net/xielinhua88/article/details/51823442
http://blog.csdn.net/zjq2008wd/article/details/17614417
https://www.cnblogs.com/angeldevil/archive/2013/03/10/2952586.html
- Android 智能指针详解 -- RefBase
- Android中的“智能指针”——RefBase
- Android framwork 分析之智能指针LightRefBase ,sp,wp,RefBase
- AndroidL 智能指针sp wp RefBase LightRefBase
- Android的“垃圾回收机制”---智能指针(android refbase类(sp wp))
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android指针管理:RefBase,SP,WP
- Android4.4 智能指针(RefBase, WP, SP)
- Android4.4 智能指针(RefBase, WP, SP)
- 智能指针RefBase、sp、wp原理与简单应用
- Android 智能指针详解 -- sp
- Android 智能指针详解 -- wp
- android RefBase
- 阿里云CloudDBA
- 服务端I/O性能大比拼:Node、PHP、Java、Go
- 0基础能学会大数据HCIE吗?
- 基础数据机构之ArrayDeque队列源码分析
- 瀑布和敏捷开发
- Android 智能指针详解 -- RefBase
- C#调用Halcon进行OCR训练时发生的错误
- SpringMVC中Model/ModelMap/ModelAndView
- 淘淘商城之商品添加功能实现
- 页面给<ul>动态添加<li>
- delphi编写ActiveX在VBS下调 返回BSTR出错
- window oracle 导入表至指定的工作空间
- MySql 5.7 修改root密码
- 使用dex-method-counts.jar来查看apk的方法数量