研究Android的時(shí)候,經(jīng)常會(huì)遇到sp、wp的東西,網(wǎng)上一搜,原來(lái)是android封裝了c++中對(duì)象回收機(jī)制。
說(shuō)明:
1. 如果一個(gè)類想使用智能指針,那么必須滿足下面兩個(gè)條件:
a. 該類是虛基類RefBase的子類或間接子類
b. 該類必須定義虛構(gòu)造函數(shù)。如virtual ~MyClass();
2. 本文以類BBinder來(lái)進(jìn)行說(shuō)明,其余類使用sp或wp的情況類似
3. 代碼路徑:frameworks/base/libs/utils/RefBase.cpp
frameworks/base/include/utils/RefBase.h
一、calss BBinder類說(shuō)明
class RefBase
class IBinder
class BpBinder class BBinder
class BBinder : public IBinder
{
...
protected:
virtual ~BBinder();
...
}
class IBinder : public virtual RefBase
{
...
protected:
inline virtual ~IBinder() { }
...
}
由上,可以看出BBinder和IBinder都是以public的方式繼承于虛基類RefBase的。
二、sp wp對(duì)象的建立過(guò)程
解析:sp<BBinder> BB_ptr(new BBinder);
這是一條定義sp指針BB_ptr的語(yǔ)句,他只想的對(duì)象是一個(gè)BBinder對(duì)象。
如圖所示。
1》首先看一下new BBinder時(shí)都做了什么,特別是和該機(jī)制相關(guān)的初始化。
c++中創(chuàng)建一個(gè)對(duì)象時(shí),需要調(diào)用去構(gòu)造函數(shù),對(duì)于繼承類,則是先調(diào)用其父類的構(gòu)造函數(shù),然后才會(huì)調(diào)用本身的
構(gòu)造函數(shù)。這里new一個(gè)BBinder對(duì)象時(shí),順序調(diào)用了:
RefBase::RefBase() : mRefs(new weakref_impl(this)) {}
inline IBinder() {}
BBinder::BBinder() : mExtras(NULL){}
主要關(guān)注的是RefBase的構(gòu)造函數(shù),
可以看出他是通過(guò)new weakref_impl(this)的結(jié)果來(lái)初始化私有成員mRefs
這里的this指向BBinder對(duì)象自身,class weakref_impl繼承于類RefBase的內(nèi)嵌類weakref_type,然后該類
weakref_impl又被類RefBase引用。類weakref_impl的構(gòu)造函數(shù)如下:
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE) // 1 << 28
, mWeak(0)
, mBase(base) // new BBinder指針
, mFlags(0)
, mStrongRefs(NULL) // sp引用鏈表指針
, mWeakRefs(NULL) // wp引用鏈表指針
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) // 1
, mRetain(false) {}
2》new BBinder返回的是BBinder對(duì)象的指針,如:sp<BBinder> BB_ptr(0x????????);
sp實(shí)際上是一個(gè)類模板,這條語(yǔ)句最終是要建立一個(gè)sp的實(shí)例化對(duì)象,叫模板類BB_ptr
這里生成BB_ptr對(duì)象所調(diào)用的構(gòu)造函數(shù)是:
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);
}
BB_ptr對(duì)象的私有指針指向剛剛前面生成的BBinder對(duì)象。
接著調(diào)用函數(shù)incStrong(),該函數(shù)是RefBase類的成員函數(shù),在子類中沒有被重載,所以這里
other->incStrong(this)的調(diào)用實(shí)際上是調(diào)用基類成員函數(shù)incStrong(this),這個(gè)this值是指向sp對(duì)象
BB_ptr的指針?,F(xiàn)在轉(zhuǎn)去查看該成員函數(shù)的實(shí)現(xiàn)。
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
/* 取得BBinder對(duì)象基類中的私有只讀指針mRefs */
refs->addWeakRef(id);
/* 調(diào)用weakref_impl類定義時(shí)實(shí)現(xiàn)的成員函數(shù)addWeakRef, 見下注釋1*/
refs->incWeak(id);
/* 調(diào)用weakref_impl類的基類weakref_type成員函數(shù)incWeak, 見下注釋2*/
refs->addStrongRef(id);
// 調(diào)用weakref_impl類定義時(shí)實(shí)現(xiàn)的成員函數(shù)addStrongRef, 見下注釋1
const int32_t c = Android_atomic_inc(&refs->mStrong);
/* 該函數(shù)實(shí)際將refs->mStrong值加1,也就是增加強(qiáng)引用計(jì)數(shù)值。但是返回值為refs->mStrong-1 */
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;
}
/* c = INITIAL_STRONG_VALUE, 第一個(gè)強(qiáng)引用產(chǎn)生的時(shí)候才會(huì)出現(xiàn)這個(gè)情況 */
Android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
/* 返回值為INITIAL_STRONG_VALUE,refs->mStrong值變成1 */
const_cast<RefBase*>(this)->onFirstRef();
}
/************************注釋1********************************/
void addWeakRef(const void* id)
{
addRef(&mWeakRefs, id, mWeak);
}
void addStrongRef(const void* id)
{
addRef(&mStrongRefs, id, mStrong);
}
addRef()是類weakref_impl的私有成員函數(shù),addWeakRef()函數(shù)引用的是public成員變量,而addRef()函數(shù)可以操作私有數(shù)據(jù)。
struct ref_entry
{
ref_entry* next;
const void* id;
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;
ref->ref = mRef;
ref->id = id;
ref->next = *refs;
*refs = ref;
/*
新出現(xiàn)的ref_entry結(jié)構(gòu)體加入到鏈表頭上,如果有n個(gè)sp指針指向同一個(gè)目標(biāo)對(duì)象
那么這里就有n個(gè)ref_entry結(jié)構(gòu)體加入到這個(gè)單鏈表中,該結(jié)構(gòu)體記錄著如下數(shù)據(jù)
1. id域記錄著對(duì)應(yīng)的sp強(qiáng)指針類對(duì)象的this值
2. ref域記錄的是當(dāng)前sp強(qiáng)指針類對(duì)象是第幾個(gè)引用目標(biāo)對(duì)象的指針
3. next域指向下一個(gè)指向目標(biāo)對(duì)象的sp強(qiáng)指針對(duì)應(yīng)的ref_entry結(jié)構(gòu)體
類RefBase的嵌套類weakref_type的子類的私有數(shù)據(jù)mRefs的私有二級(jí)指針成員mWeakRefs指向的是
最后一個(gè)sp強(qiáng)指針對(duì)應(yīng)的ref_entry結(jié)構(gòu)體指針。
總結(jié)一下:
一個(gè)目標(biāo)對(duì)象,可能被n個(gè)sp強(qiáng)指針指向,那么就存在n個(gè)class sp對(duì)象,同時(shí)每一個(gè)sp
對(duì)象在目標(biāo)對(duì)象的虛基類對(duì)象的成員類mRefs的私有二級(jí)指針成員mWeakRefs登記了一個(gè)
ref_entry結(jié)構(gòu)體,這些ref_entry結(jié)構(gòu)體的地址都是由該鏈表管理,每一個(gè)
ref_entry結(jié)構(gòu)體和哪一個(gè)sp對(duì)象對(duì)應(yīng),也由該鏈表管理。同時(shí)鏈接數(shù)就是該鏈表節(jié)點(diǎn)的
個(gè)數(shù)
*/
}
}
/************************注釋1********************************/
/************************注釋2********************************/
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
// 強(qiáng)制類型轉(zhuǎn)換,將基類指針轉(zhuǎn)換成子類指針
impl->addWeakRef(id);
// 調(diào)用類weakref_impl成員函數(shù)addWeakRef(),產(chǎn)生一個(gè)ref_entry結(jié)構(gòu)體掛載mWeakRefs鏈表上
const int32_t c = Android_atomic_inc(&impl->mWeak);
/* impl->mWeak加1,表示已存在一個(gè)weak引用。但返回值c為操作前的結(jié)果 */
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
/************************注釋2********************************/
3》上面是定義一個(gè)sp指針,下面看看定義一個(gè)wp指針式如何實(shí)現(xiàn)的。
wp<BBinder> BB_wp_ptr(BB_ptr);
下面是wp類對(duì)應(yīng)上面定義類型的構(gòu)造函數(shù)
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
this指針是指向wp對(duì)象的。createWeak()函數(shù)是RefBase類的成員函數(shù)。
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
mRefs指向的是第二步驟中產(chǎn)生的weakref_impl對(duì)象,調(diào)用基類weakref_type的成員函數(shù)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 = Android_atomic_inc(&impl->mWeak);
/* impl->mWeak有加1,但返回值為操作前的結(jié)果 */
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
三、sp、wp釋放過(guò)程
sp<BBinder> BB_SP_ptr(BB_ptr);
實(shí)際上BB_SP_ptr和前面的BB_ptr一樣,指向的是同一個(gè)BBinder對(duì)象。另外需要注意的時(shí),調(diào)用sp構(gòu)造函數(shù):
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) m_ptr->incStrong(this);
}
同樣是需要調(diào)用BBinder對(duì)象的incStrong()函數(shù),使用weakref_impl對(duì)象來(lái)管理新添加進(jìn)來(lái)的強(qiáng)引用,同時(shí)增加一個(gè)
ref_entry結(jié)構(gòu)體到weakref_impl對(duì)象的mStrongRefs,增加2個(gè)ref_entry結(jié)構(gòu)體到weakref_impl對(duì)象的mWeakRefs。
如上圖所示。
現(xiàn)在來(lái)看看釋放sp、wp指針的情況。
delete BB_SP_ptr;
將會(huì)調(diào)用如下形式的sp析構(gòu)函數(shù):
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
m_ptr指向的是前面生成的BBinder對(duì)象,調(diào)用其基類函數(shù)decStrong(this),this值是指向BB_SP_ptr對(duì)象。
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id); // 注釋3,移除mStrongRefs鏈表中和該sp對(duì)應(yīng)的ref_entry結(jié)構(gòu)體
const int32_t c = Android_atomic_dec(&refs->mStrong);
/* 強(qiáng)引用計(jì)數(shù)減1, 但返回的是操作之前的引用計(jì)數(shù)值 */
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
/* c == 1說(shuō)明剛剛removeStrongRef之前,整個(gè)系統(tǒng)中只存在一個(gè)sp對(duì)象引用目標(biāo)對(duì)象,現(xiàn)在的情況就是
系統(tǒng)中沒有任何強(qiáng)指針對(duì)象來(lái)引用目標(biāo)對(duì)象了,此時(shí)目標(biāo)對(duì)象就會(huì)被刪除釋放
*/
const_cast<RefBase*>(this)->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
delete this; // mFlags =0 ,條件成立,刪除目標(biāo)對(duì)象,這里就會(huì)刪除前面new出來(lái)的BBinder對(duì)象
}
}// 如果此時(shí)還有其他指向該目標(biāo)對(duì)象的sp指針存在的話,就不會(huì)刪除目標(biāo)對(duì)象
refs->removeWeakRef(id);
refs->decWeak(id);
/* 刪除新建目標(biāo)對(duì)象sp指針時(shí)在mWeakRefs鏈表上增加的兩個(gè)ref_entry結(jié)構(gòu)體 */
}
/*********************************注釋3*********************************/
void removeStrongRef(const void* id)
{
if (!mRetain) // mRetain 初始化成 flase
removeRef(&mStrongRefs, id);
/* 刪除mStrongRefs鏈表中對(duì)應(yīng)id的ref_entry一項(xiàng) */
/* 也就是取消了該sp對(duì)象和目標(biāo)對(duì)象的聯(lián)系 */
else
addRef(&mStrongRefs, id, -mStrong);
}
void removeRef(ref_entry** refs, const void* id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = *refs;
while (ref != NULL) {
if (ref->id == id) {
*refs = ref->next;
delete ref;
return;
}
refs = &ref->next;
ref = *refs;
}
}
}
/*********************************注釋3*********************************/
delete BB_wp_ptr;
這是刪除目標(biāo)對(duì)象的一個(gè)wp指針,會(huì)調(diào)用wp的析構(gòu)函數(shù):
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
調(diào)用weakref_type類的decWeak()函數(shù),如下:
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);// 移除weakref_impl對(duì)象mWeakRefs鏈表中對(duì)應(yīng)id的ref_entry結(jié)構(gòu)體
const int32_t c = Android_atomic_dec(&impl->mWeak);// 引用計(jì)數(shù)減1
LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return; // c == 1, 說(shuō)明這是系統(tǒng)中存在的指向目標(biāo)對(duì)象的最后一個(gè)wp指針
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if (impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
// delete impl; 是不是應(yīng)該加上這么一句,防止用戶新建了wp后,不用,馬上又刪除的情況呢?
/* 當(dāng)目標(biāo)對(duì)象的最后一個(gè)wp被析構(gòu)時(shí),如果目標(biāo)對(duì)象還沒有建立任何一個(gè)sp,那么目標(biāo)對(duì)象被刪除 */
else {
delete impl;
/* 當(dāng)目標(biāo)對(duì)象的最后一個(gè)wp被析構(gòu)時(shí),但此時(shí)和目標(biāo)對(duì)象相關(guān)的sp全部被析構(gòu),那么impl->mStrong = 0
在最后一個(gè)sp被析構(gòu)的時(shí)候,目標(biāo)對(duì)象也被釋放,所以此時(shí)只需要釋放weakref_impl對(duì)象即可
*/
}
} else {
impl->mBase->onLastWeakRef(id);
if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
delete impl->mBase;
}
}
}
四、wp升級(jí)為sp的過(guò)程
wp的定義包含了:sp<T> promote() const;
template<typename T>
sp<T> wp<T>::promote() const
{
return sp<T>(m_ptr, m_refs);
}
wp,sp互為友元類,這里promote就是以友元身份調(diào)用了sp<Binder>類的構(gòu)造函數(shù): sp(T* p, weakref_type* refs);
template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}
這里如果升級(jí)成功,那么將會(huì)產(chǎn)生一個(gè)sp對(duì)象指向目標(biāo)對(duì)象,原來(lái)的wp仍然存在。
如果升級(jí)不成功,返回NULL
看看關(guān)鍵函數(shù)refs->attemptIncStrong(this)
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);
weakref_impl* const impl = static_cast<weakref_impl*>(this);
int32_t curCount = impl->mStrong;
LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
this);
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
if (Android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
break;
}
curCount = impl->mStrong;
}// 系統(tǒng)中還有其他sp指向目標(biāo)對(duì)象的情況
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
bool allow;
if (curCount == INITIAL_STRONG_VALUE) {
// 發(fā)現(xiàn)該目標(biāo)對(duì)象還沒有一個(gè)sp對(duì)象與之相關(guān)聯(lián)的話,那么將會(huì)新建一個(gè)對(duì)目標(biāo)對(duì)象的強(qiáng)引用
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
|| impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
} else {
/*
發(fā)現(xiàn)系統(tǒng)中原來(lái)指向目標(biāo)對(duì)象的sp全部被釋放,最后一次sp釋放也將目標(biāo)對(duì)象釋放了
*/
allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
&& impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
}
if (!allow) {
decWeak(id); // 目標(biāo)對(duì)象已經(jīng)不存在了,釋放前面incWeak(id)產(chǎn)生的ref_entry結(jié)構(gòu)體
return false;
}
curCount = Android_atomic_inc(&impl->mStrong);
if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
impl->mBase->onLastStrongRef(id);
}
}
// 走完生成一個(gè)sp的必要過(guò)程,和前面介紹的是一樣
impl->addWeakRef(id);
impl->addStrongRef(id);
if (curCount == INITIAL_STRONG_VALUE) {
Android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
impl->mBase->onFirstRef();
}
return true; // 返回true
}
五、總結(jié):
1. weakref_impl對(duì)象會(huì)隨著目標(biāo)對(duì)象的生成而產(chǎn)生,但不一定會(huì)隨著目標(biāo)對(duì)象的釋放而釋放。例如:如果目標(biāo)對(duì)象被
1個(gè)sp引用,但是同時(shí)被2個(gè)wp引用,那么在sp被刪除的時(shí)候,刪除了目標(biāo)對(duì)象,但沒有刪除weakref_impl對(duì)象,
只有在最后一個(gè)wp釋放時(shí),weakref_impl對(duì)象會(huì)被釋放。
2. 一個(gè)目標(biāo)對(duì)象被多個(gè)sp指針引用,沒有wp引用的情況下。釋放這些sp的時(shí)候,delete會(huì)調(diào)用sp析構(gòu)函數(shù),
然后調(diào)用RefBase類的成員函數(shù)decStrong(), 最后一個(gè)sp被釋放時(shí),weakref_impl對(duì)象數(shù)據(jù)成員mStrong會(huì)
從1減到0(注意mStrong的初始化值為1<<28, 從這個(gè)值可以判斷出該目標(biāo)對(duì)象有沒有被sp指針引用過(guò)),
同時(shí)釋放目標(biāo)對(duì)象。
3. 一個(gè)目標(biāo)對(duì)象被多個(gè)wp指針引用,沒有sp引用的情況下。delete這些wp的時(shí)候,會(huì)調(diào)用wp的析構(gòu)函數(shù),該函數(shù)會(huì)
調(diào)用函數(shù)decWeak()。當(dāng)刪除最后一個(gè)wp的時(shí)候,代碼中只是刪除了目標(biāo)對(duì)象,而沒有釋放weakref_impl對(duì)象,
暫時(shí)沒發(fā)現(xiàn)在哪里釋放了它。
4. 一個(gè)目標(biāo)對(duì)象既有sp,又有wp來(lái)引用。如果sp先被刪除光,那么最后一個(gè)sp刪除的時(shí)候會(huì)釋放掉目標(biāo)對(duì)象,那么此時(shí)
mStrong = 0。在后續(xù)最后一個(gè)wp的釋放過(guò)程中,在decWeak()函數(shù)中就會(huì)判斷出impl->mStrong !=
INITIAL_STRONG_VALUE,而釋放掉剩下的weakref_impl對(duì)象了。如果先所以的wp刪除光,此時(shí)mWeak還等于剩余的sp
的個(gè)數(shù),所以此時(shí)的釋放情況,同第2小點(diǎn)的說(shuō)明。
5. 從wp定義來(lái)看,wp是不能直接操作對(duì)象的,必須先升級(jí)為sp才行。這個(gè)升級(jí)的過(guò)程是依靠函數(shù)promote()來(lái)完成的。
升級(jí)成功,返回新生成的sp對(duì)象指針,升級(jí)失敗,返回NULL。需要注意的是,如果目標(biāo)對(duì)象之前有過(guò)sp指向,但后來(lái)
將所有的sp釋放完之后,此時(shí)目標(biāo)對(duì)象是不存在的,那么此時(shí)用戶還想將指向該目標(biāo)對(duì)象的wp升級(jí)為sp的話,
此時(shí)就返回NULL。那么這個(gè)時(shí)候我們應(yīng)該delete這些剩下的wp。