Android中的智能指針

指針

在傳統的C++編程中,指針的使用一直是一把雙刃劍。指針賦予了我們直接操作硬件地址的能力,但同時也帶來了諸多問題。其中最常見的問題可以歸納為三個:

1、指針沒有初始化。

2、new了對象以后沒有及時delete。

3、野指針。指針指向的對象已經被delete了,但是指針并沒有被置空。這種情況多發生在多個指針同時指向同一個對象,其中某個指針釋放了對象的情況。

為了解決上述這些問題,Android引入了引用計數技術,只有當引用計數為0的時候,才允許并且自動釋放對象。但傳統的引用計數技術,對于父子循環依賴的情況是無能為力的。因此又衍生出了強弱引用計數技術。因為強弱引用計數其實包含了普通引用計數的部分,所以我們就直接介紹強弱引用計數的實現方式。

強弱引用計數

引用計數需要解決的關鍵點有三點:

一、如何得知一個新的引用指向了該對象,如何得知指向該對象的舊引用已經失效

二、該對象的引用計數值如何維護,存儲在哪里,何時進行修改。

三、釋放該對象的合適的時機是什么時候?

Android中的強弱引用計數的總體思路是比較簡單的。

1、為所有的需要使用到引用計數的對象提供一個基類,這個基類中有一個內部類專門負責維護該對象的強引用計數和弱引用計數。

2、定義一個強指針類sp,重載其所有賦值相關操作,當把對象賦值給sp的時候,sp會增加該對象的引用計數,當sp不再指向該對象的時候,會在sp的析構函數中減少該對象的引用計數

3、定義弱指針類wp,和sp類似,唯一的區別是沒有重載解引用操作。因此當wp需要真正使用所指向的對象時需要提升至強指針。

4、對象主要有兩種生命周期管理方式。一是由強指針控制生命周期,當強引用計數為0時就回收該對象。弱指針不能再提升為強指針。一種是由弱指針控制生命周期,只有當強引用計數和弱引用計數同時為0的時候,才可以回收該對象。

主要思路如上4點,剩下的都是具體的實現方式以及某些特殊情況的處理。比如從來沒有強指針指向過該對象,而生命周期又由強指針控制的情況等等。

舉個栗子

舉一個不恰當的生活的例子來類比一下:

A是個燒餅鋪的老板,能夠制作燒餅并且出售。

為了擴大銷量,A允許他人簽訂代理合同進行分銷。也允許他人僅僅簽訂意向合同,在之后再簽訂正式的代理合同。但是簽訂代理合同之前必須先簽訂意向合同。

以上是約束條件。

這個時候B和A簽訂了一份代理合同放在A那里。C也和A簽訂了一份代理合同放在A那里。于是A就知道他有兩個銷售代理,那他們存續期間自己是不能關門的,因為他們隨時可能需要取貨。

這時候,D也想做A的代理但又下不了決心,于是跟A簽訂了一份意向合同,只是表示自己有這個想法,如果決定了再簽訂正式的代理合同。

這個時候,A手里就有三份意向合同,兩份代理合同。

假設B, C決定不再做A的代理,取消了跟A的代理以及意向合同。這時候A手里就只剩下和D的意向合同了。

此時就分化為幾種情況。

A決定關門了。也就是說A關不關門,只看自己手上的代理合同,而不看意向合同。而當D想要前來正式簽訂代理合同的時候發現A已經關門了,代理合同簽訂失敗。

這就是生命周期由強引用計數控制,而強引用計數為0,弱指針提升為強指針失敗的例子。

A沒有關門,而是等待D前來取消了意向合同才關門。

這就是生命周期由弱引用計數控制,而弱引用計數變化為0的情況。

而如果A沒有關門,直到D前來又簽訂了一份正式的代理合同。

那么這就是生命周期由弱引用計數控制,而弱指針成功提升為強指針的情況。

從這個例子中我們可以看到一個問題:如果A手里的意向合同有聯系方式的話,是不是可以直接打電話告訴D,自己打算關門了而不用等D上門來簽合同的時候才知道呢?也即RefBase中除了引用計數的值之外,是不是也可以保存一個wp和sp列表呢?

1、引用產生和失效的判斷

針對第一點,Android中定義了兩個類模板類sp和wp。分別是strongPointer和weakPointer的縮寫。他們內部都持有一個T* m_ptr的對象引用。并且重載了所有賦值和構造相關的函數。也就是說當出現諸如sp<Object> sp_object = object;的調用時,sp類的重載函數就會被調用。而這些重載函數內部的主要邏輯就是增加object對象的強引用計數值(增加強引用計數的同時,弱引用計數也會同時增加)。wp也是同理,只不過增加的是弱引用計數值。于是通過sp和wp去引用一個對象,就解決了如何得知新的引用產生的問題。同理,引用失效的時機就在sp和wp的析構函數中,其主要邏輯也就是減少object的強弱引用計數。

所以我們這里明確,要使用強弱引用技術,就必須使用sp和wp去引用一個對象。普通的指針是沒有這種效果的。sp和wp的代碼如下:

sp

template<typename T>

class sp

{

? ? public:

? ? ? ? ? ?typedef typename RefBase::weakref_type weakref_type; //暫時可以忽略

? ? ? ? ? ?inline sp():m_ptr(0) {}? //構造函數


? ? ? ? ? /*以下這段就是賦值相關的操作符重載以及構造相關的重載函數,當對sp賦值或者構造sp的時候,這些函數就會被調用。其中除了各函數原本的邏輯之外,最重要的邏輯就是修改引用對象的引用計數*/

? ? ? ? ? ?sp(T* other);? ? ?

? ? ? ? ? ?sp(const sp<T>& other);?

? ? ? ? ? ?template<typename U> sp(U* other);?

? ? ? ? ? ?template<typename U> sp(const sp<U>& other);

? ? ? ? ? ?sp& operator = (T* other);

? ? ? ? ? ?sp& operator = (const sp<T> & other);

? ? ? ? ? ?template<typename U> sp& operator = (const sp<U>& other);

? ? ? ? ? ?template<typename U> sp& operator = (U* other);

? ? ? ? ? /*以上*/

? ? ? ? ? ~sp;? ?//析構函數? ?減少所引用對象的引用計數

? ? ? ? ? //解引用部分,也即調用sp->以及sp.操作時,實際調用的是其所指向的對象m_ptr的操作。

? ? ? ? ? inline T& operator* () const {return *m_ptr;}

? ? ? ? ? inline T* operator->() const {return m_ptr;}

? ? ? ? ? inline T* get() const {return m_ptr;}

? ? ? ? ? ...

? ? ? ? ? //其余比較操作符重載的部分,因為對于sp的比較實際上應該是m_ptr之間的比較

? ? ? ? ? ...

? ? ?private:

? ? ? ? ? ?sp(T* p,? weakref_type* refs);? ?//暫時可以忽略

? ? ? ? ? ?T* m_ptr;? //指向的真實的對象。

}

由于C++提供了操作符重載操作,所以sp重載了->和*等操作符,使得對于sp的操作等同于直接對于m_ptr的操作。同時重載了賦值操作符=,使得賦值的時候我們有機會進行一些操作。構造函數以及拷貝構造函數也做了適當的處理。

wp

wp的主要實現和sp一致,重載比較操作符,解引用操作符,賦值操作符等。在構造函數,拷貝函數以及賦值時增加引用對象的引用計數。在析構函數中減少引用對象的引用計數。其主要代碼如下:

template <typename T>

class wp

{

? ? public:

? ? ? ? typedef typename RefBase::weakref_type weakref_type;

? ? ? ? inline wp(): m_ptr(0) {}

? ? ? ? wp(T* other);

? ? ? ? wp(const wp<T>& other);

? ? ? ? wp(const sp<T>& other);

? ? ? ? template<typename U> wp(U* other);

? ? ? ? template<typename U> wp(const sp<U>& other);

? ? ? ? template<typename U> wp(const wp<U>& other);

? ? ? ? wp& operator = (T* ohter);

? ? ? ? wp& operator = (const wp<T>& other);

? ? ? ?wp& operator = (const sp<T>& other);

? ? ? ?template<typename U> wp& operator = (U* other);

? ? ? ?template<typename U> wp& operator = (const wp<U>& other);

? ? ? ?template<typename U> wp&operator = (const sp<U>& other);

? ? ? ?~wp();

? ? ? ?sp<T> promote() const;? ?//用于將弱引用提升為強引用

? ? ? ?//其余操作符重載部分

? ? ? ?...

private:

? ? ? ? T* m_ptr;? ?//引用的對象

? ? ? ? weakref_type* m_refs;

}

可以看到wp和sp的主要結構是一致的。但是wp多了一個promote函數以及m_refs成員變量。前者是為了將弱引用提升為強引用用的。后者稍后會提及。

2、引用計數值的維護

在1中,我們知道當sp或者wp被賦值以及析構的時候,都會去修改對象的引用計數值。但是這個引用計數究竟是放在哪里的?放在wp或者sp中是不合適的,因為指向同一個對象的sp或者wp可能同時有多個。那既然所有的sp和wp都能夠獲得引用的對象,那我們能夠想到的就是由所引用的對象自己去維護這個引用計數了。因此,Android為所有需要實現引用計數的對象提供了一個基類。RefBase. RefBase擁有一個weakref_impl類型的成員變量mRefs,weakref_impl又具有int_32_t類型的mStrong以及mWeak兩個成員變量。他們分別負責記錄一個對象的強引用計數和弱引用計數。所有關于引用計數的操作最終實際上就是修改這兩個變量的值。需要注意的是weakref_impl是繼承了weakref_type類型。weakref_type類型是在RefBase中定義的。

RefBase

class RefBase?

{

public:

? ? void? incStrong(const void* id) const;

? ? void decStrong(const void* id) const;


? ? class weakref_type?

? ? {

? ? ?public:?

? ? ? ? ?RefBase*? refBase() const;

? ? ? ? ?void incWeak(const void* id);

? ? ? ? ?void decWeak(const void* id);

? ? ? ? ?bool attemptIncStrong(const void* id);

? ? ?}


protected:

? ?RefBase();??

? ?virtual ~RefBase();

? ?emum {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//默認情況該對象的生命周期由強引用計數控制

? ? ? ? OBJECT_LIFETIME_WEAK = 0x0001,? ?//該對象的生命周期由弱引用計數控制

? ? ? ? OBJECT_LIFETIME_FOREVER = 0x0003;? //該對象的生命周期由用戶自己維護

? ?};

? ?void? extendObjectLifetime(int32_t mode);? ?//修改該對象的生命周期控制條件

? ?enum {

? ? ? ?FIRST_INC_STRONG = 0x0001;

? ?}

? ? virtual void onFirstRef();? ?//第一次有引用指向了這個對象。Andorid系統中很多組件的初始化都是放在這個函數里的。

? ? virtual void onLastStrongRef(const void* id);? //強引用計數變為了0.

? ? virtual bool onIncStrongRef(const void* id);

? ? virtual void onLastWeakRef(const void* id);? //弱引用計數變為了0.

private :

? ? RefBase(const RefBase& o);

? ? RefBase operator = (const Refbase& o);

? ? weakref_impl* const mRefs;? //真正維護強弱引用計數的對象

}

weakref_impl

class RefBase::weakref_impl : public RefBase::weakref_type?

{

? ? public:

? ? ? ?volatile int32_t mStrong;

? ? ? ?volatile int32_t mWeak;

? ? ? ?RefBase* const mBase;

? ? ? ?volatile int32_t mFlags;

? ? ? ?weakref_impl(RefBase* base)

? ? ? ? ? ?:mStrong(INITIAL_STRONG_VALUE)

? ? ? ? ? ? ,mWeak(0)

? ? ? ? ? ? ,mBase(base)

? ? ? ? ? ? ,mFlgas(0)?

? ? ? ? {}

? ? ? ? //debug相關函數

? ? ? ?...

}

通過一張類圖,我們可以更為清晰的了解三者之間的關系。

我們在觀察下incStrong, decStrong, incWeak, decWeak的實現。

incStrong

void RefBase::incStrong(const void * id) const

{

? ? weakref_impl* const refs = mRefs;

? ? refs->incWeak(id);? //增加強引用的時候必須同時增加弱引用。所以弱引用計數的數值是肯定大于強引用計數的。而弱引用計數為0的時候,強引用計數肯定為0.

? ? const int32_t c= android_atomic_inc(&refs->mStrong);? ? //c是atomic_inc之前的值

? ? if (c != INITIAL_STRONG_VALUE) {? //說明不是第一次

? ? ? ? ?return;

? ? }

? ? android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);? //如果是第一次,需要減去INITAL_STRONG_VALUE。

? ? const_cast<RefBase*>(this)->onFirstRef();??

}


給refs->mStrong設定一個INITIAL_STRONG_VALUE的初始值的意義在于區分這個值是不是被修改過。而如果初始值是0的話,就分不清楚是本來就為0,還是經過一系列增增減減后又變為了0.這跟后面的生命周期有直接關系。如果mStrong的值為INITAL_STRONG_VALUE,那就說明沒有任何強引用引用過這個對象。

incWeak

void RefBase::weakref_type::incWeak(const void* id)

{

? ? weakref_impl* const impl = static_cast<weakref_impl*>(this);

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

}

decStrong

void RefBase::decStrong(const void* id) const

{

? ? weakref_impl* const refs = mRefs;

? ? const int32_t c = android_atomic_dec(&refs->mStrong);

? ? refs->decWeak(id);

? ? ...

}

decWeak

void RefBase::weakref_type::decWeak(const void* id)

{

? ? weakref_impl* const impl = static_cast<weakref_impl>(this);

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

? ?...

}

可以看到IncStrong, incWeak, decStrong, decWeak的主要邏輯都是修改weakref_impl的成員變量mStrong以及mWeak的值。

至此,結合第1節以及第2節的內容,我們可以得出操作強弱引用計數的大體步驟。

1、需要使用引用計數的對象必須繼承自RefBase。 RefBase中有個實際類型為weakref_impl,父類型為weakref_type的mRefs成員,其包含兩個成員變量mStrong和mWeak. 所有RefBase上調用的incStrong, incWeak, decWeak, decStrong最終的操作都是修改這兩個值。

2、要使用引用計數,必須用spwp去指向一個繼承自RefBase的對象。在sp和wp初始化操作以及析構函數中,會調用RefBase相關的操作引用計數的方法。

簡化后的理解就是:

sp或者wp初始化或者析構------>獲取RefBase類型的成員變量m_ptr------>獲取RefBase的weakref_impl類型的mRefs成員變量------>修改mStrong以及mWeak的值。

3、對象的生命周期

前兩節中,我們已經清楚了對象是怎么感知到指向自身的引用變化以及引用計數的數值更改的流程。但是這個引用計數值究竟是如何變化的,又怎么和對象的生命周期產生關聯的,我們還沒有提及。

主要是兩點。一是RefBase對象回收的時機,二是weakref_impl對象回收的時機。

在第二節中,我們提到過。RefBase的生命周期有三種形式:OBJECT_LIFETIME_STRONG,OBJECT_LIFETIME_WEAK,OBJECT_LIFETIME_FOREVER。分別代表強引用計數控制生命周期,弱引用計數控制生命周期,以及用戶自己控制其生命周期。

OBJECT_LIFETIME_STRONG

這種方式下。RefBase對象的生命周期完全由強引用計數控制。所以我們很容易的就能想到當weakref_imp的mStrong值為0的時候也就可以釋放RefBase對象了。因此我們可以在decStrong中去進行判斷。事實上也是如此。

void RefBase::decStrong(const void* id) const

{

? ? weakref_impl* const refs = mRefs;

? ? const int32_t c = android_atomic_dec(&refs->mStrong);

? ? if (c == 1) {

? ? ? ? ?const_cast<RefBase*>(this)->onLastStrongRef(id);

? ? ? ? //生命周期由強引用計數控制,且強引用計數值為0,那么就直接回收這個對象。

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

? ? ? ? ? ? ? delete this;

? ? ? ? ?}

? ? }

? ? refs->decWeak(id);

}

當RefBase的生命周期控制方式不為OBJECT_LIFETIME_WEAK時,也即完全由強引用計數決定時,那么在強引用計數為0時就可以直接delete this了。

OBJECT_LIFETIME_WEAK

如果RefBase的生命周期由弱引用計數控制。那么在強引用計數為0的時候,就不能直接delete對象。而必須延遲到decWeak中去進行判斷。當

void RefBase::weakref_type::decWeak(const void* id)

{

? ? weakref_impl* const impl = static_cast<weakref_impl*>(this);

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

? ? if (c != 1) return;? //弱引用計數不為0,就直接返回

? ? if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {?

? ? ? ? if (impl->mStrong == INITIAL_STRONG_VALUE)??

? ? ? ? ? ? ?//弱引用計數為0,且強引用計數為初始值,且生命周期不由弱引用計數控制

? ? ? ? ? ? //就需要刪除該對象。因為沒有強引用指向過該對象,也就不可能有decStrong的機會去回收這個對象。

? ? ? ? ? ? ? delete impl->mBase;??

? ? ? ? ?else

? ? ? ? ? ? ? //生命周期由強引用計數控制,那么現在弱引用計數為0,強引用計數也必然為0,那么在decStrong中該對象已經被回收過了。

? ? ? ? ? ? ? //只需要刪除weakref_impl對象即可

? ? ? ? ? ? ? ?delete impl;??

? ? } else {? //生命周期由弱引用計數控制

? ? ? ? ? ? impl->mBase->onLastWeakRef(id);

? ? ? ? ? ? //生命周期由弱引用計數控制,且弱引用計數為0,那么就需要回收該對象。

? ? ? ? ? ? if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {

? ? ? ? ? ? ? ? ?delete impl->mBase;

? ? ? ? ? ? }

? ? }

}

整理一下,RefBase對象的回收時機有以下幾種情況:

1、生命周期由強引用計數控制,有強引用指向過該對象,那么對象在decStrong中發現mStrong為0時回收。

2、生命周期由強引用計數控制,從來沒有強引用指向過該對象,有弱引用指向過該對象。那么對象在decWeak中發現mWeak為0時回收。

3、生命周期由弱引用計數控制,mWeak為0時回收該對象。

weakref_impl的回收時機則有兩個,一是在RefBase的析構函數中。另一個則是在decWeak中的delete impl處。

如果是由弱引用計數控制RefBase生命周期的話,那么當RefBase對象析構時,那弱引用計數肯定為0,強引用計數也肯定為0,所以在RefBase的析構函數中就可以安全回收weakref_impl對象。

如果是由強引用計數控制RefBase生命周期的話,那么當RefBase對象析構時,強引用計數為0,弱引用計數不一定為0,那么就不能夠在RefBase析構函數中去回收weakref_impl。而只能在弱引用計數為0時去進行回收。

因此現在RefBase的生命周期徹底和其內部的weakref_impl的mWeak和mStrong的值,以及wp和sp的構造和析構函數聯系在一起了。

簡而言之就是:

wp以及sp的析構函數會觸發所引用的RefBase對象的decStrong或者decWeak函數,從而改變RefBase的weakref_impl類型的成員變量的mWeak以及mStrong值。

從而觸發RefBase對象的回收邏輯。

弱引用提升為強引用

在上一節中,比較特別的一種情況就是強引用計數為0,弱引用計數不為0的情況,且生命周期由強引用計數控制的情況。在這種情況下,實際上RefBase對象已經被回收了,但是仍然有弱引用指向了這個對象。那么怎么防止弱引用使用這個已經被回收的對象呢?

Android中使用的方法是不重載wp類的解引用操作符,operator*以及operator->,使得wp無法直接使用m_ptr對象,必須調用wp的promote方法將wp升級為sp才能夠使用。因此wp的promote方法是關鍵。

template<typename T>

sp<T> wp<T>::promote() const

{

? ? ?return sp<T><m_ptr, m_refs);? //調用強引用的構造器

}

template<typename T>

sp<T>::sp(T* p, weakref_type* refs):m_ptr(p && refs->attemptIncStrong(this)) ? p : 0) {}? //試圖調用弱引用所指向對象的weakref_impl成員的attemptIncStrong方法。

bool RefBase:;weakref_type::attemptIncStrong(const void* id)?

{

? ? incWeak(id);

? ? weakref_impl* const impl = static_cast<weakref_impl*>(this);

? ? int32_t curCount = impl->mStrong;

? ?//如果強引用計數不為0,且不為初始值,那肯定是可以增加強引用計數的。

? ? while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {? //自旋

? ? ? ?//cmpxchg是個原子操作,全稱是compareAndChange,只有mStrong的值為curCount時,才會將其值修改為curCount + 1, 否則修改失敗。

? ? ? //這樣子便可以防止其他線程先一步修改了mStrong的值。在ConcurrentHashmap以及輕量級鎖中都用到了這個原子操作。

? ? ? ? if (android_atomic_cmpxchg(curCount, curCount + 1, &impl->mStrong) == 0) {

? ? ? ? ? ? ? //修改curCount值與前面while中判斷的間隙期間,引用計數值沒有變化,那么實際上是可以直接返回true了,不會進入后面的分支條件

? ? ? ? ? ? ? break;

? ? ? ? }

? ? ? ? //修改curCount值與前面while中判斷的間隙期間,引用計數值發生變化了。將curCount更新為mStrong的最新值,再次嘗試修改。

? ? ? ? curCount = impl->mStrong;?

? ? }

? ? //這里退出循環有兩種情況,一種是修改成功break了,那么是不會進入下面的條件的。

? ?//另一個是修改失敗了并且獲取最新的引用計數值時發現其值為0了。那么會進入下面的分支。

? ? if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {? //之前強引用計數為0,或者為初始值

? ? ? ? ?bool allow;

? ? ? ? ?if (curCount == INITIAL_STRONG_VALUE) {??

? ? ? ? ? ??//該對象之前并沒有被強引用指向過,那么只要生命周期不由弱引用控制,那么該對象就不可能被回收過。那么就可以提升為強指針

? ? ? ? ? ?//如果該對象生命周期由弱引用控制,顯然該對象也未被回收,那么就看調用該對象的onIncStrongAttempted方法看該對象是否允許被提升為強指針。

? ? ? ? ? //onIncStrongAttempted方法參數為FIRST_INC_STRONG時都是返回true的

? ? ? ? ? ? ?allow = (impl->mFlags&OBJECT_LIFETIME_WEAK)? != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

? ? ? ? ?} else {

? ? ? ? ? ?//該對象的強引用計數為0,那么只有生命周期弱引用控制的時候,才可能沒有被回收,因為當前正有一個弱引用指向對象。

? ? ? ? ? //那么就調用該對象的onIncStrongAttempted方法看該對象是否允許被提升為強指針。

? ? ? ? ? //onIncStrongAttempted方法參數為FIRST_INC_STRONG時都是返回true的

? ? ? ? ? ? allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

? ? ? ? ?}

? ? ? ? if (!allow) {

? ? ? ? ? ? ?decWeak(id);

? ? ? ? ? ? ?return false;

? ? ? ? }

? ? ? ?curCount = android_atomic_inc(&impl->mStrong);? //如果允許的話就增加強引用計數

? ? }

? ??//修正mStrong 的值并且調用onFirstRef方法。

? ? if (curCount == INITIAL_STRONG_VALUE) {??

? ? ? ? ?android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);

? ? ? ? ?impl->mBase->onFirstRef();??

? ? }

? ? return true;

}

//可以看到當參數為FIRST_INC_STRONG時,是一直返回true的

bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)?

{

? ? return (flags& FIRST_INC_STRONG) ? true : false;

}

所以結合這段將弱指針提升為強指針的代碼,我們可以看到:

attemptIncStrong的主要邏輯就是判斷該對象是不是已經回收了,實際上只要是該對象沒有被回收,那么都是可以被提升到強指針的。(由于這段代碼里onIncStrongAttempted都是返回true,所以可以忽略)

如果強引用計數值大于0且不等于INITIAL_STRONG_VALUE,那么就肯定可以提升為強指針。這也是while那段邏輯所判斷的。

如果強引用計數等于0,那么只有生命周期由弱引用計數控制的時候才沒有被回收。

如果強引用計數等于INITIAL_STRONG_VALUE,那么也是可以被提升為強指針的。

以上的代碼和解說基本上都是照搬《Android系統源代碼情景分析》中的,簡化了某些不必要的代碼部分。但是仍然過于繁瑣。我覺得作為一個Android應用層開發的程序員,對于框架層的代碼,還是抱著不求甚解的態度去閱讀比較好。抓大放小,理解關鍵實現方式,而不應該對其中的細節糾纏過多。因為細節在你真正去實現的時候,你自然會發現也能夠解決,并不是阻擋你實現的關鍵障礙。


大致情況就是這樣子。如果以后找到更好的表述方式的話會再進行改進。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容