我們的“三板斧”,其實就是三個例子。相信這三板斧劈下去,你會很容易理解它們。
**例子1**
~~~
/類A從RefBase派生,RefBase是萬物的始祖
class A:public RefBase
{
//A沒有任何自己的功能
}
int main()
{
A* pA =new A;
{
//注意我們的sp,wp對象是在{}中創建的,下面的代碼先創建sp,然后創建wp
sp<A>spA(A);
wp<A>wpA(spA);
//大括號結束前,先析構wp,再析構sp
}
}
~~~
例子夠簡單吧?但也需一步一步分析這斧子是怎么劈下去的。
1. RefBase和它的影子
類A從RefBase中派生。使用的是RefBase構造函數。代碼如下所示:
**RefBase.cpp**
~~~
RefBase::RefBase()
:mRefs(new weakref_impl(this))//注意這句話
{
//mRefs是RefBase的成員變量,類型是weakref_impl,我們暫且叫它影子對象
//所以A有一個影子對象
}
~~~
mRefs是引用計數管理的關鍵類,需要進去觀察。它是從RefBase的內部類weakref_type中派生出來的。
先看看它的聲明:
~~~
class RefBase::weakref_impl : public RefBase::weakref_type
//從RefBase的內部類weakref_type派生
~~~
由于Android頻繁使用C++內部類的方法,所以初次閱讀Android代碼時可能會有點不太習慣,C++的內部類和Java內部類相似,但不同的是,它需要一個顯示的成員指向外部類對象,而Java內部類對象就有一個隱式的成員指向外部類對象。
說明:內部類在C++中的學名叫nested class(內嵌類)。
**RefBase.cpp::weakref_imple構造**
~~~
weakref_impl(RefBase* base)
:mStrong(INITIAL_STRONG_VALUE) //強引用計數,初始值為0x1000000
,mWeak(0) //弱引用計數,初始值為0
,mBase(base)//該影子對象所指向的實際對象
,mFlags(0)
,mStrongRefs(NULL)
,mWeakRefs(NULL)
,mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
,mRetain(false)
{
}
~~~
如你所見,new了一個A對象后,其實還new了一個weakref_impl對象,這里稱它為影子對象,另外我們稱A為實際對象。
這里有一個問題:影子對象有什么用?
可以仔細想一下,是不是發現影子對象成員中有兩個引用計數?一個強引用,一個弱引用。如果知道引用計數和對象生死有些許關聯的話,就容易想到影子對象的作用了。
按上面的分析,在構造一個實際對象的同時,還會悄悄地構造一個影子對象,在嵌入式設備的內存不是很緊俏的今天,這個影子對象的內存占用已不成問題了。
2. sp上場
程序繼續運行,現在到了
~~~
sp<A> spA(A);
~~~
請看sp的構造函數,它的代碼如下所示:(注意,sp是一個模板類,對此不熟悉的讀者可以去翻翻書,或者干脆把所有出現的T都換成A。)
**RefBase.h::sp(T*other)**
~~~
template<typename T>
sp<T>::sp(T* other) //這里的other就是剛才創建的pA
:m_ptr(other)// sp保存了pA的指針
{
if(other) other->incStrong(this);//調用pA的incStrong
}
~~~
OK,戰場轉到RefBase的incStrong中。它的代碼如下所示:
**RefBase.cpp**
~~~
void RefBase::incStrong(const void* id) const
{
//mRefs就是剛才RefBase構造函數中new出來的影子對象
weakref_impl*const refs = mRefs;
//操作影子對象,先增加弱引用計數
refs->addWeakRef(id);
refs->incWeak(id);
......
~~~
先來看看影子對象的這兩個weak函數都干了些什么。
(1)眼見而心不煩
先來看第一個函數addWeakRef,代碼如下所示:
**RefBase.cpp**
~~~
void addWeakRef(const void* /*id*/) { }
~~~
呵呵,addWeakRef啥都沒做,因為這是release版走的分支。調試版的代碼我們就不討論了,它是給創造RefBase、 sp,以及wp的人調試用的。
調試版分支的代碼很多,看來創造它們的人,也為不理解它們之間的曖昧關系痛苦不已。
總之,一共有這么幾個不用考慮的函數,我們都已列出來了。以后再碰見它們,干脆就直接跳過的是:
~~~
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) { }
~~~
繼續我們的征程。再看incWeak函數,代碼如下所示:
**RefBase.cpp**
~~~
void RefBase::weakref_type::incWeak(const void*id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id); //上面說了,非調試版什么都不干
const int32_tc = android_atomic_inc(&impl->mWeak);
//原子操作,影子對象的弱引用計數加1
//千萬記住影子對象的強弱引用計數的值,這是徹底理解sp和wp的關鍵
}
~~~
好,我們再回到incStrong,繼續看代碼:
**RefBase.cpp**
~~~
......
//剛才增加了弱引用計數
//再增加強引用計數
refs->addStrongRef(id);//非調試版這里什么都不干
//下面函數為原子加1操作,并返回舊值。所以c=0x1000000,而mStrong變為0x1000001
const int32_t c =android_atomic_inc(&refs->mStrong);
if (c!= INITIAL_STRONG_VALUE) {
//如果c不是初始值,則表明這個對象已經被強引用過一次了
return;
}
//下面這個是原子加操作,相當于執行refs->mStrong +(-0x1000000),最終mStrong=1
android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong);
/*
如果是第一次引用,則調用onFirstRef,這個函數很重要,派生類可以重載這個函數,完成一些
初始化工作。
*/
const_cast<RefBase*>(this)->onFirstRef();
}
~~~
說明:android_atomic_xxx是Android平臺提供的原子操作函數,原子操作函數是多線程編程中的常見函數,讀者可以學習原子操作函數知識,本章后面將對其做介紹。
(2)sp構造的影響
sp構造完后,它給這個世界帶來了什么?
- 那就是RefBase中影子對象的強引用計數變為1,弱引用計數也變為1。
更準確的說法是,sp的出生導致影子對象的強引用計數加1,弱引用計數加1。
(3)wp構造的影響
繼續看wp,例子中的調用方式如下:
~~~
wp<A> wpA(spA)
~~~
wp有好幾個構造函數,原理都一樣。來看這個最常見的:
**RefBase.h::wp(constsp<T>& other)**
~~~
template<typename T>
wp<T>::wp(const sp<T>& other)
:m_ptr(other.m_ptr) //wp的成員變量m_ptr指向實際對象
{
if(m_ptr) {
//調用pA的createWeak,并且保存返回值到成員變量m_refs中
m_refs = m_ptr->createWeak(this);
}
}
~~~
**RefBase.cpp**
~~~
RefBase::weakref_type* RefBase::createWeak(constvoid* id) const
{
//調用影子對象的incWeak,這個我們剛才講過了,將導致影子對象的弱引用計數增加1
mRefs->incWeak(id);
returnmRefs; //返回影子對象本身
}
~~~
我們可以看到,wp化后,影子對象的弱引用計數將增加1,所以現在弱引用計數為2,而強引用計數仍為1。另外,wp中有兩個成員變量,一個保存實際對象,另一個保存影子對象。sp只有一個成員變量用來保存實際對象,但這個實際對象內部已包含了對應的影子對象。
OK,wp創建完了,現在開始進入wp的析構。
(4)wp析構的影響
wp進入析構函數,這表明它快要離世了。
**RefBase.h**
~~~
template<typename T>
wp<T>::~wp()
{
if(m_ptr) m_refs->decWeak(this); //調用影子對象的decWeak,由影子對象的基類實現
}
~~~
**RefBase.cpp**
~~~
void RefBase::weakref_type::decWeak(const void*id)
{
//把基類指針轉換成子類(影子對象)的類型,這種做法有些違背面向對象編程的思想
weakref_impl*const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//非調試版不做任何事情
//原子減1,返回舊值,c=2,而弱引用計數從2變為1
constint32_t c = android_atomic_dec(&impl->mWeak);
if (c !=1) return; //c=2,直接返回
//如果c為1,則弱引用計數為0,這說明沒用弱引用指向實際對象,需要考慮是否釋放內存
// OBJECT_LIFETIME_XXX和生命周期有關系,我們后面再說。
if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if(impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
else {
delete impl;
}
} else{
impl->mBase->onLastWeakRef(id);
if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
delete impl->mBase;
}
}
}
~~~
OK,在例1中,wp析構后,弱引用計數減1。但由于此時強引用計數和弱引用計數仍為1,所以沒有對象被干掉,即沒有釋放實際對象和影子對象占據的內存。
(5)sp析構的影響
下面進入sp的析構。
**RefBase.h**
~~~
template<typename T>
sp<T>::~sp()
{
if(m_ptr) m_ptr->decStrong(this); //調用實際對象的decStrong。由RefBase實現
}
~~~
**RefBase.cpp**
~~~
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);//調用影子對象的removeStrongRef,啥都不干
//注意,此時強弱引用計數都是1,下面函數調用的結果是c=1,強引用計數為0
constint32_t c = android_atomic_dec(&refs->mStrong);
if (c== 1) { //對于我們的例子, c為1
//調用onLastStrongRef,表明強引用計數減為0,對象有可能被delete
const_cast<RefBase*>(this)->onLastStrongRef(id);
//mFlags為0,所以會通過delete this把自己干掉
//注意,此時弱引用計數仍為1
if((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
delete this;
}
......
}
~~~
先看delete this的處理,它會導致A的析構函數被調用;再看A的析構函數,代碼如下所示:
**例子1::~A()**
~~~
//A的析構直接導致進入RefBase的析構。
RefBase::~RefBase()
{
if(mRefs->mWeak == 0) { //弱引用計數不為0,而是1
delete mRefs;
}
}
~~~
RefBase的delete this自殺行為沒有把影子對象干掉,但我們還在decStrong中,可接著從delete this往下看:
**RefBase.cpp**
~~~
....//接前面的delete this
if ((refs->mFlags&OBJECT_LIFETIME_WEAK)!= OBJECT_LIFETIME_WEAK) {
delete this;
}
//注意,實際數據對象已經被干掉了,所以mRefs也沒有用了,但是decStrong剛進來
//的時候就保存mRefs到refs了,所以這里的refs指向影子對象
refs->removeWeakRef(id);
refs->decWeak(id);//調用影子對象decWeak
}
~~~
**RefBase.cpp**
~~~
void RefBase::weakref_type::decWeak(const void*id)
{
weakref_impl*const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//非調試版不做任何事情
//調用前影子對象的弱引用計數為1,強引用計數為0,調用結束后c=1,弱引用計數為0
constint32_t c = android_atomic_dec(&impl->mWeak);
if (c!= 1) return;
//這次弱引用計數終于變為0,并且mFlags為0, mStrong也為0。
if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if(impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
else {
delete impl; //impl就是this,把影子對象自己干掉
}
} else{
impl->mBase->onLastWeakRef(id);
if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
delete impl->mBase;
}
}
}
~~~
好,第一板斧劈下去了!來看看它的結果是什么。
3. 第一板斧的結果
第一板斧過后,來總結一下剛才所學的知識:
- RefBase中有一個隱含的影子對象,該影子對象內部有強弱引用計數。
- sp化后,強弱引用計數各增加1,sp析構后,強弱引用計數各減1。
- wp化后,弱引用計數增加1,wp析構后,弱引用計數減1。
完全徹底地消滅RefBase對象,包括讓實際對象和影子對象滅亡,這些都是由強弱引用計數控制的,另外還要考慮flag的取值情況。當flag為0時,可得出如下結論:
- 強引用為0將導致實際對象被delete。
- 弱引用為0將導致影子對象被delete。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結