1关于C++ Layer的内存回收机制
Android C++层的内存收回主要是通过三个类来实现,分别是RefBase,sp,wp;
SP和WP是两个智能指针模板类,sp是strong pointer,wp则是weak pointer,亦我们常说的强引用和弱引用;实例化sp和wp这两个模板类的类型必须是派生自RefBase的类
1.1
因为这个类拥有对内存回收机制的默认实现,所以android上想要支持内存回收机制的类必须派生自RefBase
下面简单介绍下成员变量和成员函数:
mRefs:
weakref_impl对象,派生于RefBase::weakref_type, 包含了对strong ref和weak ref的具体实现,也就是说RefBase中只包含了一些对外的标准操作,具体的实现在weakref_impl内
void incStrong(const void *id):
强引用计数加1,参数id主要用在debug时跟踪调试,一般都为sp或者wp的对象指针
void decStrong(const void *id):
强引用计数减1,参数id含义同上
void forceIncStrong(const void *id):
强制引用计数加1
Int32_t getStrongCount():
获去强引用计数值
weakref_type * createWeak(const void *id)
弱引用计数加1,然后返回weakref_impl对象
weakref_type* getWeakRefs()
获取weakref_impl对象
void extendObjectLifetime(int32_t mode):
扩展对象的生命期,默认为0,可设置为
OBJECT_LIFETIME_FOREVER = 0x0003
这几个参数的作用在下面会详细描述
virtual void onFirstRef()
虚函数,在第一次新增引用计数时,会调用此函数,接下去的其他函数都类似
上面也有提到了,RefBase有一个内部基类weakref_type,
它主要包含了对弱引用计数的基本操作,
void incWeak(const void*id):
弱引用计数加1,id参数的意义同上
void decWeak(const void *id):
弱引用计数减1,id同上
bool attemptIncStrong(const void *id):
尝试增加强引用计数,这个函数会在wp promote获取sp时被调用,主要确认wp promote为sp是否成功
bool attemptIncWeak(const void *id):
尝试增加弱引用计数,这个功能只在object lifetime设置为OBJECT_LIFETIME_FOREVER有效
Int32_t getWeakCount():
获取弱引用计数值
在RefBase中,可以通过extendObjectLifetime来设置lifetime,有三种life time:
1:default(0),强引用和弱引用的默认行为,不管弱应用计数的值为多少,只要强引用计数的值为0,就释放对象
2:OBJECT_LIFETIME_WEAK,在这种状态下,如果强引用为0时,对象不会被释放,只有在弱引用计数为0的情况下,对象才会被释放
3:OBJECT_LIFETIME_WEAK | OBJECT_LIFETIME_FOREVER,在这种状态下,对象永不会释放
第三种情况比较猛,设置了,除非主动delete raw pointer,否则在sp和wp的规则下,是不会被释放的,当然,promote也是永远都会成功的
在增加或者减少强引用计数的同时,弱引用计数也会被增加或减少,它们总是配对出现的,下面简单看下几个关键部分的代码:
//增加强引用计数
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
//store the object which makes strong reference up, just for track & debug, it is an empty //function
refs->addWeakRef(id);
//increment weak reference
//store the object which makes strong reference up, just for track & debug, if not in debug, it //is an empty function, nothing will be done.
#if PRINT_REFS
#endif
if (c != INITIAL_STRONG_VALUE)
}
//if the previous value of mStrong equals INITIAL_STRONG_VALUE
//first for increment strong reference
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
//notify first reference done
}
//增加弱引用计数
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
//如上面所写,保存id只为做debug用
}
接下是两个减少引用计数的函数,因为这两个函数涉及到对象的销毁,所以讲的详细点
//减少强引用计数
void RefBase::decStrong(const void* id) const
{
#if PRINT_REFS
#endif
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
//强引用减完后为零,尝试销毁对象
}
//减少弱引用计数
void RefBase::weakref_type::decWeak(const void* id)
{
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
//LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase) ;
} else {
}
如果对上面一会释放imple->mBase,一会释放weakref_impl有疑问,继续看RefBase的析构函数:
RefBase::~RefBase()
{
}
RefBase被销毁时,只有当弱引用计数为0时,才会释放weakref_imp对象,上面decWeak中第一和第三个delete,直接释放impl->mBase,肯定没问题,因为这时候弱引用计数已经为0,weakref_imp对象在析构中正常被释放
再看第二个delete,在默认life time下,如果RefBase通过sp建立了强引用,在强引用为0的情况下在执行RefBase::decStrong中的以下代码,
if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
}
RefBase对象肯定会被释放,在释放时调用析构时,由于mRefs->mWeak == 0不成立,内部weaktype_imp对象不会被释放,所以这里需要delete impl以释放内部引用管理对象
1.2
创建sp:
sp(const sp<T>& other):从已有的sp对象拷贝构造
创建wp:
wp(const sp<T>& other):从已有的sp对象拷贝
1.3
如果想通过已有的wp对象获取对应的内建对象,需要调用promote来尝试提升为sp,然后通过sp来判断promote是否成功,如果成功,说明内建对象还存在,可以继续使用,反之,需要创建新的内建对象
下面来详细查看下promote做了哪些操作:
template<typename T>
sp<T> wp<T>::promote() const
{
}
template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
{
}
调用引用管理类的函数attemptIncStrong来尝试增加强引用计数,如成功,说明raw pointer保存的对象还未被释放,可以继续使用,反之,返回false,promote失败
接下去详细看下attemptIncStrong的实现:
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
//如果强引用计数<=0或者初始值,就代表对象已经被释放了吗?
//不一定
// attempting to acquire first strong reference...
// Attempting to revive the object...
// an unneeded reference.
// (No, this is not pretty.)
#if PRINT_REFS
#endif
}
attemptIncStrong成功,promote成功,继续使用已有的Refbase对象实例,如果失败了,则需重新创建新的对象。
1.4
在android中,在实现基于RefBase的类中,大部分都使用默认的生命期,只有BpBinder会调用extendObjectLifetime(OBJECT_LIFETIME_WEAK)来更改默认生命期;针对默认生命期,其用处和Java的强引用和弱引用类似,下面用代码来粗略的描述下sp和wp的使用:
class A : public RefBase{
//…
}
sp<A> sp_inst(new A());
wp<A> wp_weak(sp_inst);
然后wp在使用前,需要
sp<A> sp_promote = wp.promote();
//promote 失败
If (sp_promote == NULL)
{
//重新创建对象
sp<A> sp_new(new A());
sp_promote = sp_new;
}