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 wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
}
weakref_impl 继承自weakref_type,扩展了部分接口,其实扩展的接口是debug使用的,只有打开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
然后看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_REFS
ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
if (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;当第一次调用时,则回调Refbase.onFirstRef()
同理decStrong 也是将mStrong和mWeak 同时-1, 最后一次调用时回调RefBase.onLastStrongRef().
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_REFS
ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
LOG_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 %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;
}
}
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_ENABLED
CallStack::CallStackUPtr 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 && CALLSTACK_ENABLED
ref->stack = CallStack::getCurrent(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;
}
#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
}
}