RAII - 安卓中的智能指针
概念 sp wp RefBase
是什么
system/core/libutils/RefBase.cpp
system/core/libutils/include/utils/RefBase.h
system/core/libutils/StrongPointer.cpp
system/core/libutils/include/utils/StrongPointer.h
Android在标准库之外,自定义了以下两种智能指针类型:
-
强指针
sp
(strong pointer),弱指针wp
(weak pointer)都是模板类 -
sp 和
share_ptr
概念相同。wp 和weak_ptr
概念相同。sp
和wp
has-aRefBase
-
弱指针仅仅记录对象的地址,不能通过弱指针来访问该对象。要想访问弱指针所指向的对象,需首先通过wp类所提供的promote()方法将弱指针升级为强指针。
-
弱指针所指向的对象是有可能在其它地方被销毁的。如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。
-
支持使用 sp
和 wp
的对象,必须继承RefBase类。观察Android 中使用sp
和 wp
的地方,传进来的模板参数都是继承自RefBase
,例如:
// MediaPlayer是支持使用强指针和弱指针的对象
class MediaPlayer : public BnMediaPlayerClient,
public virtual IMediaDeathNotifier
{
public:
MediaPlayer();
~MediaPlayer();
// 父类是 BnMediaPlayerClient 和 IMediaDeathNotifier,
// 多继承可能出现菱形继承,因此 虚继承自 RefBase
class IMediaDeathNotifier: virtual public RefBase
{
public:
IMediaDeathNotifier() { addObitRecipient(this); }
virtual ~IMediaDeathNotifier() { removeObitRecipient(this); }
//随便找个,可以看到是继承RefBase,注意的是虚拟继承。
怎么用
// 使用智能指针的类必须继承自 RefBase
class Ressource : public RefBase {
Ressource(int){}
void test() {}
}
{ // 作用域开始
// 强引用 sp 构造函数有很多,这里简单列举两个
Ressource* p = new Ressource(1);
sp<Ressource> sp1(p); // 1
sp<Ressource> sp1 = new Ressource(1); // 2
// sp::make 提供内存连贯性&缓存命中: 构建一个 sp 对象,其内部new一个资源对象,在将成员变量 m_ptr 指针指向它
static sp<Ressource> sp1 = sp<Ressource>::make(1); // 3
// 通过强引用,操作指针指向的对象
sp1->test();
// 不能直接通过弱引用使用对象,升级为强指针再使用
wp<Ressource> wp1(p); // 弱引用
sp<Ressource> sp2 = wp1.promote();
if(sp2 != NULL) { // sp重载了 != 原本spRessource2与 NULL 不是同一类型
sp2->test();
}
} // 作用域结束,调用强引用对象的析构函数,释放掉 p 指针指向的内存
对比标准库
为什么不直接用标准库?
为什么不用标准库?
1、历史原因!C++11推出 shared_ptr 和 weak_ptr之前,Android就已经需要存在了。
2、特殊的功能:有些功能是针对特定使用场景定制的(显然不符合 C++ 标准)。
例如,特殊的接口:
template<typename T>
class sp {
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
}
template<typename T>
void sp<T>::force_set(T* other) {
other->forceIncStrong(this);
m_ptr = other;
}
例如,智能指针有两种模式
- 强引用控制
OBJECT_LIFETIME_STRONG
(默认,且绝大多数情况下都是强引用控制) - 弱引用控制
OBJECT_LIFETIME_WEAK
可通过 void RefBase::extendObjectLifetime(int32_t mode)
函数切换。强/弱引用控制的切换,通常在被管理的目标类的构造函数中调用:
// system/core/libutils/include/utils/RefBase.h
enum {
OBJECT_LIFETIME_STRONG = 0x0000, //强引用控制
OBJECT_LIFETIME_WEAK = 0x0001, //弱引用控制
// 掩码值,可使用 flag&OBJECT_LIFETIME_MASK 的形式来获取 flag 的最低位数值
OBJECT_LIFETIME_MASK = 0x0001
};
// frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(Handle&& handle) {
// 调用函数修改智能指针模式
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
}
例如,神奇的功能:
static void check_not_on_stack(const void* ptr) {
实现上的区别
从被管理的资源的角度来看:
标准库的 shared_ptr,”管理它所持有的 裸指针“。
- 被管理的资源——裸指针所指向的对象,可以是任意类型。
- 处于"被管理状态",不会对资源本身造成什么影响,没有负担。
Android 实现的 sp,wp ”操作它所持有的 RefBase类的计数“。
- 被管理的资源——必须是 RefBase类,即被管理要求原有类型必须继承 RefBase类。
- 处于"被管理状态",意味着
- 资源类RefBase 自身保存计数,保存的强引用计数归零后自己执行
delete this
- sp wp 会去操作,让资源类去管理自身保存的计数
- 资源类RefBase 自身保存计数,保存的强引用计数归零后自己执行
优缺点
Android这样不使用 STD 智能指针的做法,
优点:总结来说就是,客制化的美~
-
允许进行根据需求自定义的修改/优化。
前文介绍过的,特殊接口,强/弱引用控制
-
安卓fwk中普遍存在跨进程“引用资源”的的情况,RefBase 自行计数方便IPC情境下的管理。
-
方便且臃肿的 debug 函数
缺点:总结来说就是,增大对象本身的开销
-
对象占用内存增高—— 作为操作系统必要,但是其它场景不需要的开销
诸如函数
RefBase::getStrongCount()
,RefBase::weakref_type::trackMe()
-
资源类有时候需要虚继承 RefBase —— 为了解决菱形继承而不可避免的选择。因此相较于使用标准库的智能指针,每次更改计数都不得不承担虚函数表带来的开销。
-
不同于标准库这件事情本身就会影响可读性,引入新的复杂度。
你自己看看复杂不复杂,臃肿不臃肿
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id); //删除弱引用
//减少对象的弱引用计数,并且返回减少之前的值,存储在c中
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);
/*
如果c不等于1则不用进行处理,
如果c=1,说明弱引用计数为0,则强引用计数必定也为0,
则考虑如何释放该对象
*/
if (c != 1) return; //还有其他引用在用这个指针,直接返回
/*
释放方式取决于当前对象的生命周期控制标志mFlags的值
0,只要强引用计数为0,系统则自动释放这个对象
OBJECT_LIFETIME_WEAK,只有强引用计数和弱引用计数都为0,系统才会自动释放这个对象
OBJECT_LIFETIME_FOREVER,系统永远不会释放这个对象,需要开发者手动释放
*/
atomic_thread_fence(std::memory_order_acquire);
// ...
RefBase类
首先,这屌东西里面有什么。它能干啥?
内部类 weakref_type
RefBase
类 有两个内部类:定义 & 实现 引用计数维护接口
class weakref_type
:定义接口class weakref_impl
:具体实现(weakref_type
继承weakref_impl
)
成员变量RefBase::mRefs
,类型就是刚刚提到的内部类 weakref_impl* const
——描述对象的引用计数。
内部类weakref_type
提供有类方法:
- 增加/减少 弱引用计数:
weakref_type::incWeak
,weakref_type::decWeak
- 维护对象的强/弱引用计数:
weakref_type::attemptIncStrong
,weakref_type::attemptIncWeak
class RefBase {
friend class weakref_type;
class weakref_type {/*...*/};
class weakref_impl;
//使用一个weakref_impl对象来描述对象的引用计数
weakref_impl* const mRefs;
class RefBase::weakref_impl : public RefBase::weakref_type
成员函数
RefBase
类 有一系列 成员函数
-
关于强引用:
incStrong
,incStrongRequireStrong
,decStrong
,forceIncStrong
-
关于弱引用:
createWeak
,getWeakRefs
,
createWeak
类方法,返回weakref_type
类型的指针。
sp wp
sp
-
sp::m_ptr
的类型是T*
即RefBase *
——sp has-a RefBase -
控制计数,最终调用:
RefBase::incStrong
和RefBase::decStrong
方法
template <typename T>
class sp {
// T 类型就是 RefBase 的子类
T* m_ptr;
};
// decStrong 和incStrong的具体实现,在RefBase类中。
void RefBase::incStrong(const void* id) const
void RefBase::decStrong(const void* id) const
wp
wp::m_refs
的类型是RefBase::weakref_type *
- 控制计数,最终调用:
RefBase::incStrong
和RefBase::decStrong
方法
// RefBase::weakref_type中实现
RefBase::weakref_type* RefBase::createWeak(const void* id) const
void RefBase::weakref_type::incWeak(const void* id)
void RefBase::weakref_type::decWeak(const void* id)
强引用 sp
通过 初始化/传入参数 设置m_ptr
,m_ptr
必须是RefBase
类的派生类(虚继承),从而使用 RefBase::incStrong和RefBase::decStrong修改RefBase本身的引用计数。
sp构造时:初始化sp中RefBase类型的指针 m_ptr,并调用指针incStrong()进行计数加1
sp析构时:指针T *m_ptr需要将计数减1
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);
}
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
弱引用 wp
成员变量 wp::m_ptr
,wp::m_refs
wp::m_ptr
类型是RefBase
类型的指针,指向资源RefBase
本身。wp::m_refs
类型是RefBase::weakref_type
,即资源RefBase
的成员变量RefBase::mRefs
——用于指向管理资源的内部类。
构造/移动&拷贝/赋值/清空时,以上两个成员变量被同时修改。
通过成员变量wp::m_refs
(类型为RefBase::weakref_type
)的成员函数去修改资源RefBase计数。
template <typename T>
class wp
{
typedef typename RefBase::weakref_type weakref_type;
T* m_ptr;
weakref_type* m_refs;
};
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
源码注释 RefBase
接口
class RefBase
{
public:
//增加强引用计数
void incStrong(const void* id) const;
//减少强引用计数
void decStrong(const void* id) const;
// (wp中的m_refs调用)
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
void forceIncStrong(const void* id) const;
int32_t getStrongCount() const;
// 定义了内部类:weakref_type weakref_impl
class weakref_type
{
public:
RefBase* refBase() const;
//增加弱引用计数 (wp中的m_refs调用)
void incWeak(const void* id);
//减少弱引用计数 (wp中的m_refs调用)
void decWeak(const void* id);
//维护对象的强引用计数
bool attemptIncStrong(const void* id);
//维护对象的弱引用计数
bool attemptIncWeak(const void* id);
// debug用函数
int32_t getWeakCount() const;
void printRefs() const;
void trackMe(bool enable, bool retain);
};
// Debug 函数...
// 允许自定义的Destroyer
class Destroyer {
friend class RefBase;
public:
virtual ~Destroyer();
private:
virtual void destroy(RefBase const* base) = 0;
};
void setDestroyer(Destroyer* destroyer);
protected:
RefBase();
virtual ~RefBase();
// 生命周期有关的flag,函数...
// 一堆其它功能的虚函数...
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
//使用一个weakref_impl对象来描述对象的引用计数
weakref_impl* const mRefs;
};
强引用
decStrong
RefBase类的成员函数decStrong减少对象的引用计数
实现如下:
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;
}
}
refs->decWeak(id);//如果不是最后一个,需要减少弱引用链表
}
incStrong
RefBase类的成员函数incStrong 增加对象的引用计数
实现如下:
frameworks/base/libs/utils/RefBase.cpp
//RefBase类的成员函数incStrong来增加对象的引用计数
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->addWeakRef(id);
refs->incWeak(id);//增加对象的引用计数
refs->addStrongRef(id);//增加对象的强引用计数
const int32_t c = android_atomic_inc(&refs->mStrong);
LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
if (c != INITIAL_STRONG_VALUE) {
return;
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
//如果对象第一次被强指针引用,进行通知
const_cast<RefBase*>(this)->onFirstRef()
}
弱引用
incWeak
只有RefBase::weakref_type
的对象才能调用 incWeak
和decWeak
。
frameworks/base/libs/utils/RefBase.cpp
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
const int32_t c = android_atomic_inc(&impl->mWeak);
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
decWeak
只有RefBase::weakref_type
的对象才能调用 incWeak
和decWeak
。
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id); //删除弱引用
//减少对象的弱引用计数,并且返回减少之前的值,存储在c中
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);
/*
如果c不等于1则不用进行处理,
如果c=1,说明弱引用计数为0,则强引用计数必定也为0,
则考虑如何释放该对象
*/
if (c != 1) return; //还有其他引用在用这个指针,直接返回
/*
释放方式取决于当前对象的生命周期控制标志mFlags的值
0,只要强引用计数为0,系统则自动释放这个对象
OBJECT_LIFETIME_WEAK,只有强引用计数和弱引用计数都为0,系统才会自动释放这个对象
OBJECT_LIFETIME_FOREVER,系统永远不会释放这个对象,需要开发者手动释放
*/
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);
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
if (impl->mBase) {
if (impl->mDestroyer) {
impl->mDestroyer->destroy(impl->mBase);
} else {
delete impl->mBase;//如果没有其他引用了,就释放当前指针
}
}
}
}
}
weakref_type 具体实现
weakref_type类
定义了引用计数维护接口,具体的实现由weakref_impl类
实现。
frameworks/base/libs/utils/RefBase.cpp
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong; //描述强引用计数
volatile int32_t mWeak; //描述弱引用计数
RefBase* const mBase; //指向它所引用的对象的地址
/*
mFlags取值范围
0,表示对象的生命周期只收强引用计数影响
OBJECT_LIFETIME_WEAK, 表示对象的生命周期同时受强引用计数和弱引用计数影响
OBJECT_LIFETIME_FOREVER,表示对象的生命周期完全不受强引用指针和弱引用指针影响
*/
volatile int32_t mFlags;//描述对象生命周期控制方式
Destroyer* mDestroyer;
#if !DEBUG_REFS
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
, mDestroyer(0)
{
}
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else
....//省略部分不重要内容
#endif
};
析构函数
RefBase类
中成员变量mRefs
的解析函数的实现。
frameworks/base/libs/utils/RefBase.cpp
RefBase::~RefBase()
{
/*
如果发现对象的弱引用计数为0,则在释放RefBase对象的同时也将引用计数对象mRefs一起释放掉。
mRefs对象在RefBase的构造函数中被创建,指向weakref_impl,
如果RefBase对象都不存在了,并且mWeak也为0,mRefs也没有什么存在的必要了。
强引用计数一定是小于弱引用计数的,所以强引用计数为0时弱引用计数仍有可能大于0。
所以在弱引用计数大于0的情况下我们只释放RefBase对象,留下mRefs对象继续使用。
*/
if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
if (mRefs->mWeak == 0) {
delete mRefs;
}
...
}
}
标签:const,RAII,void,weakref,计数,引用,安卓中,RefBase,指针
From: https://blog.csdn.net/weixin_41733034/article/details/142903605