日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android sp wp实例,android sp wp详解

發(fā)布時(shí)間:2025/3/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android sp wp实例,android sp wp详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

研究的時(shí)候,經(jīng)常會(huì)遇到sp、wp的東西,網(wǎng)上一搜,原來是android封裝了c++中對(duì)象回收機(jī)制。

說明:

1. 如果一個(gè)類想使用智能指針,那么必須滿足下面兩個(gè)條件:

a. 該類是虛基類RefBase的子類或間接子類

b. 該類必須定義虛構(gòu)造函數(shù)。如virtual ~MyClass();2. 本文以類BBinder來進(jìn)行說明,其余類使用sp或wp的情況類似3. 代碼路徑:frameworks/base/libs/utils/RefBase.cppframeworks/base/include/utils/RefBase.h

一、calss BBinder類說明

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ì)象的建立過程

解析:spBB_ptr(new BBinder);

這是一條定義sp指針BB_ptr的語句,他只想的對(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ù),

可以看出他是通過new weakref_impl(this)的結(jié)果來初始化私有成員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ì)象的指針,如:spBB_ptr(0x????????);

sp實(shí)際上是一個(gè)類模板,這條語句最終是要建立一個(gè)sp的實(shí)例化對(duì)象,叫模板類BB_ptr

這里生成BB_ptr對(duì)象所調(diào)用的構(gòu)造函數(shù)是:

templatesp::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的指針。現(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 =?_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è)情況 */

_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);

/* 返回值為INITIAL_STRONG_VALUE,refs->mStrong值變成1 */

const_cast(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(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 =?_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)的。

wpBB_wp_ptr(BB_ptr);

下面是wp類對(duì)應(yīng)上面定義類型的構(gòu)造函數(shù)

templatewp::wp(const sp& 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(this);

impl->addWeakRef(id);

const int32_t c =?_atomic_inc(&impl->mWeak);

/* impl->mWeak有加1,但返回值為操作前的結(jié)果 */

LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);

}

三、sp、wp釋放過程

spBB_SP_ptr(BB_ptr);

實(shí)際上BB_SP_ptr和前面的BB_ptr一樣,指向的是同一個(gè)BBinder對(duì)象。另外需要注意的時(shí),調(diào)用sp構(gòu)造函數(shù):

templatesp::sp(const sp& other)

: m_ptr(other.m_ptr)

{

if (m_ptr) m_ptr->incStrong(this);

}

同樣是需要調(diào)用BBinder對(duì)象的incStrong()函數(shù),使用weakref_impl對(duì)象來管理新添加進(jìn)來的強(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)在來看看釋放sp、wp指針的情況。

delete BB_SP_ptr;

將會(huì)調(diào)用如下形式的sp析構(gòu)函數(shù):

templatesp::~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 =?_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說明剛剛removeStrongRef之前,整個(gè)系統(tǒng)中只存在一個(gè)sp對(duì)象引用目標(biāo)對(duì)象,現(xiàn)在的情況就是

系統(tǒng)中沒有任何強(qiáng)指針對(duì)象來引用目標(biāo)對(duì)象了,此時(shí)目標(biāo)對(duì)象就會(huì)被刪除釋放

*/

const_cast(this)->onLastStrongRef(id);

if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {

delete this; // mFlags =0 ,條件成立,刪除目標(biāo)對(duì)象,這里就會(huì)刪除前面new出來的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ù):

templatewp::~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(this);

impl->removeWeakRef(id);// 移除weakref_impl對(duì)象mWeakRefs鏈表中對(duì)應(yīng)id的ref_entry結(jié)構(gòu)體

const int32_t c =?_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, 說明這是系統(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的過程

wp的定義包含了:sppromote() const;

templatespwp::promote() const

{

return sp(m_ptr, m_refs);

}

wp,sp互為友元類,這里promote就是以友元身份調(diào)用了sp類的構(gòu)造函數(shù): sp(T* p, weakref_type* refs);

templatesp::sp(T* p, weakref_type* refs)

: m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)

{

}

這里如果升級(jí)成功,那么將會(huì)產(chǎn)生一個(gè)sp對(duì)象指向目標(biāo)對(duì)象,原來的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(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 (_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)中原來指向目標(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 =?_atomic_inc(&impl->mStrong);

if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {

impl->mBase->onLastStrongRef(id);

}

}

// 走完生成一個(gè)sp的必要過程,和前面介紹的是一樣

impl->addWeakRef(id);

impl->addStrongRef(id);

if (curCount == INITIAL_STRONG_VALUE) {

_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指針引用過),

同時(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來引用。如果sp先被刪除光,那么最后一個(gè)sp刪除的時(shí)候會(huì)釋放掉目標(biāo)對(duì)象,那么此時(shí)

mStrong = 0。在后續(xù)最后一個(gè)wp的釋放過程中,在decWeak()函數(shù)中就會(huì)判斷出impl->mStrong !=

INITIAL_STRONG_VALUE,而釋放掉剩下的weakref_impl對(duì)象了。如果先所以的wp刪除光,此時(shí)mWeak還等于剩余的sp

的個(gè)數(shù),所以此時(shí)的釋放情況,同第2小點(diǎn)的說明。

5. 從wp定義來看,wp是不能直接操作對(duì)象的,必須先升級(jí)為sp才行。這個(gè)升級(jí)的過程是依靠函數(shù)promote()來完成的。

升級(jí)成功,返回新生成的sp對(duì)象指針,升級(jí)失敗,返回NULL。需要注意的是,如果目標(biāo)對(duì)象之前有過sp指向,但后來

將所有的sp釋放完之后,此時(shí)目標(biāo)對(duì)象是不存在的,那么此時(shí)用戶還想將指向該目標(biāo)對(duì)象的wp升級(jí)為sp的話,

此時(shí)就返回NULL。那么這個(gè)時(shí)候我們應(yīng)該delete這些剩下的wp。

總結(jié)

以上是生活随笔為你收集整理的android sp wp实例,android sp wp详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。