1 背景
cpp 开发中,指针是比较难处理,如果是一个大系统,管理不善很可能出现内存泄漏(new之后没释放)/野指针(已释放,但还有其他再使用)等问题发生。
java 使用引用的方式,不开放指针的操作,所以java side基本没这个问题。
有效解决上述问题的方式,andorid 设计一套方法(智能指针)自动管理指针的释放和引用情况,同时内部借助引用计数的方式解决在还有人使用时不释放指针(引用计数变为0时,才会析构指针所指对象)。
这边还一个问题是相互引用的情况,这样引用个数都不为0,就都不能释放了。所以android 设计了强引用sp和弱引用wp,向java取经。
2 sp/wp 定义
android 的封装的只能指针是sp/wp(strong pointer/weak pointer)。
code 路径是:
system/core/libutils/include/utils/RefBase.h
system/core/libutils/include/utils/StrongPointer.h
sp 和wp是模板类,模板的实现部分必须在header文件(*.h)中
看下图,
sp和wp就是封装了m_ptr指针,然后重载了一些操作符,并提供了clear/set等少部分api。
二者的不同点是,wp明显多了部分内容,就是weakref_type和与之相关的一些api
typedef typename RefBase::weakref_type weakref_type;
weakref_type就是RefBase::weakref_type。
后面再看 weakref_type的实现部分。
3 sp/wp 的实现
下面截取了部分sp和wp的实现部分,构造/析构/重载操作符等函数,基本实现都是一样的,都是调用的指针里面的操作,如incStrong/decStrong/createWeak/incWeak/decWeak。
但该指针是模板类型,所有这个指针模板就需要有一个公共父类,定义了上述的标准接口,才可以让sp和wp不会报错。
system/core/libutils/include/utils/StrongPointer.h
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);
}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;
}
system/core/libutils/include/utils/RefBase.h
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(const sp<T>& other): m_ptr(other.m_ptr)
{m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}template<typename T>
wp<T>::~wp()
{if (m_ptr) m_refs->decWeak(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;
}
4 模板指针指向类:RefBase
想思考下为什么定义这个父类,一个原因是模板的写法定义统一的api,另一个原因是将引用计数统一放到这个父类中存储。
将引用计数存放到Refbase中,就是指针指向的实体中,如果在智能指针中就是单独计数了,因为每个智能指针是独立的,而指向的实体才是唯一的。
RefBase的结构体
看其构造和析构函数,new weakref_impl,weakref_impl是什么呢,看下图
RefBase::RefBase(): mRefs(new weakref_impl(this))
{
}RefBase::~RefBase()int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {delete mRefs;}} else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {......}// For debugging purposes, clear mRefs. Ineffective against outstanding wpst_cast<weakref_impl*&>(mRefs) = nullptr;
}
weakref_impl 继承自weakref_type,扩展了部分接口,其实扩展的接口是debug使用的,只有打开debug后才有效,否则接口时空的。
#if !DEBUG_REFSexplicit 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
然后看RefBase的incStrong的实现部分,
system/core/libutils/RefBase.cpp
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_REFSALOGD("incStrong of %p from %p: cnt=%dn", this, id, c);
#endifif (c != INITIAL_STRONG_VALUE) {return;}int32_t old __unused = 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();
}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);ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
这边其实就是weakref_type 和weakref_impl的相关实现,操作std::atomic<int32_t>进行+1。
incStrong 是将mStrong和mWeak 同时+1;当第一次调用时,则回调FirstRef()
同理decStrong 也是将mStrong和mWeak 同时-1, 最后一次调用时回调LastStrongRef().
void RefBase::decStrong(const void* id) const
{weakref_impl* const refs = mRefs;refs->removeStrongRef(id);const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFSALOGD("decStrong of %p from %p: cnt=%dn", this, id, c);
#endifLOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "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;// The destructor does not delete refs in this case.}}......refs->decWeak(id);
}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);LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "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(td::memory_order_relaxed);if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {if (impl->mStrong.load(std::memory_order_relaxed)== INITIAL_STRONG_VALUE) {ALOGW("RefBase: Object at %p lost last weak reference ""before it had a strong reference", impl->mBase);} else {// ALOGV("Freeing refs %p of old RefBase %pn", 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;}
}
5 wp的差异
观察wp 的实现code,与sp的差异点是,sp是直接使用ptr的incStrong/decStrong, wp则使用refs的incWeak/decWeak, 而Refbase中就没有提供incWeak/decWeak的接口,而是使用内部类weakref_impl提供这些接口。
为什么要这样处理呢?
因为Refbase和weakref_impl是可以脱离依托关系的,在Refbase被释放后,weakref_impl可以继续存在使用,所以wp使用weakref_impl 操作更安全。
6 delete的地方
从上面的code,可以看到
构造RefBase时,也new weakref_impl,
那我们看Refbase和weakref_impl 是析构的呢,整理表格如下
RefBase | weakref_impl | |
OBJECT_LIFETIME_STRONG | decStrong且strong count =1 | decWeak且weak count为1,且strong count不为INITIAL_STRONG_VALUE |
OBJECT_LIFETIME_WEAK | decWeak 且weak count =1 | RefBase 析构 |
Refbase和weakref_impl是可以脱离依托关系的, 在OBJECT_LIFETIME_STRONG模式下,当sp 对应的Refbase 释放后,weakref_impl继续存在,直到wp不在使用。
OBJECT_LIFETIME_WEAK 模式下,sp 不会控制RefBase的释放,在wp失效后,Refbase释放,接着weakref_impl释放。
7 weakref_impl 提供了debug 模式
在DEBUG_REFS 宏后,有debug模式存在,
它内部实现了一个链表,记录id和callstack,
这边需要通过api trackMe,设置mTrackEnabled = true
调用printRefs 可以将链表及callstack 信息输出到文件中
/data/debug/***.stack
【注意callstack 的code是在另一个so包中,"libutilscallstack", 如果打印callback 需要加上这个so,在apk/bin/或者相关so中奥】
struct ref_entry{ref_entry* next;const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLEDCallStack::CallStackUPtr stack;
#endifint32_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 f->ref = mRef;ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLEDref->stack = CallStack::getCurrent(2);
#endifref->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;}#if CALLSTACK_ENABLEDCallStack::logStack(LOG_TAG);
#endif}}
本文发布于:2024-01-29 01:42:10,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170646373311807.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |