Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(3)...
?提供引用計數器的類RefBase我們就暫時介紹到這里,后面我們再結合智能指針類一起分析,現在先來看看強指針類和弱指針類的定義。強指針類的定義我們在前面介紹輕量級指針的時候已經見到了,就是sp類了,這里就不再把它的代碼列出來了。我們來看看它的構造函數的實現:
??這里傳進來的參數other一定是繼承于RefBase類的,因此,在函數的內部,它調用的是RefBase類的incStrong函數,它定義在frameworks/base/libs/utils/RefBase.cpp文件中:?
??成員變量mRefs是在RefBase類的構造函數中創建的:
?在這個incStrong函數中,主要做了三件事情:
?一是增加弱引用計數:
?二是增加強引用計數:
? ?三是如果發現是首次調用這個對象的incStrong函數,就會調用一個這個對象的onFirstRef函數,讓對象有機會在對象被首次引用時做一些處理邏輯:
?這里的c返回的是refs->mStrong加1前的值,如果發現等于INITIAL_STRONG_VALUE,就說明這個對象的強引用計數是第一次被增加,因此,refs->mStrong就是初始化為INITIAL_STRONG_VALUE的,它的值為:#define?INITIAL_STRONG_VALUE?(1<<28)??
? ?這個值加1后等于1<<28 + 1,不等于1,因此,后面要再減去-INITIAL_STRONG_VALUE,于是,refs->mStrong就等于1了,就表示當前對象的強引用計數值為1了,這與這個對象是第一次被增加強引用計數值的邏輯是一致的。
? ? ? ? 回過頭來看弱引用計數是如何增加的,首先是調用weakref_impl類的addWeakRef函數,我們知道,在Release版本中,這個函數也不做,而在Debug版本中,這個函數增加了一個ref_entry對象到了weakref_impl對象的mWeakRefs列表中,表示此weakref_impl對象的弱引用計數被增加了一次。接著又調用了weakref_impl類的incWeak函數,真正增加弱引用計數值就是在這個函數實現的了,weakref_impl類的incWeak函數繼承于其父類weakref_type的incWeak函數:
? 增加弱引用計數是下面語句執行的:const?int32_t?c?=?android_atomic_inc(&impl->mWeak); ?? ?但是前面為什么又調用了一次addWeakRef函數呢?前面不是已經調用過了嗎?在Release版本中,因為weakref_impl類的addWeakRef函數是空實現,這里再調用一次沒有什么害處,但是如果在Debug版本,豈不是冗余了嗎?搞不清,有人問過負責開發Android系統Binder通信機制模塊的作者Dianne Hackborn這個問題,他是這樣回答的:?
?http://groups.google.com/group/android-platform/browse_thread/thread/cc641db8487dd83
?? ? ? ?Ah I see. ?Well the debug code may be broken, though I wouldn't leap to that?
?? ? ? ?conclusion without actually testing it; I know it has been used in the?
?? ? ? ?past. ?Anyway, these things get compiled out in non-debug builds, so there?
?? ? ? ?is no reason to change them unless you are actually trying to use this debug?
?? ? ? ?code and it isn't working and need to do this to fix it.?
?? ? ? ?既然他也不知道怎么回事,我們也不必深究了,知道有這么回事就行。
?? ? ? ?這里總結一下強指針類sp在其構造函數里面所做的事情就是分別為目標對象的強引用計數和弱引和計數增加了1。
? ? ? ? 再來看看強指針類的析構函數的實現:
? ? ?同樣,這里的m_ptr指向的目標對象一定是繼承了RefBase類的,因此,這里調用的是RefBase類的decStrong函數,這也是定義在frameworks/base/libs/utils/RefBase.cpp文件中:
??這里的refs->removeStrongRef函數調用語句是對應前面在RefBase::incStrong函數里的refs->addStrongRef函數調用語句的,在Release版本中,這也是一個空實現函數,真正實現強引用計數減1的操作是下面語句:
? ?如果發現減1前,此對象的強引用計數為1,就說明從此以后,就再沒有地方引用這個目標對象了,這時候,就要看看是否要delete這個目標對象了:
??在強引用計數為0的情況下,如果對象的標志位OBJECT_LIFETIME_WEAK被設置了,就說明這個對象的生命周期是受弱引用計數所控制的,因此,這時候就不能delete對象,要等到弱引用計數也為0的情況下,才能delete這個對象。
?
? ? ? ? 接下來的ref->removeWeakRef函數調用語句是對應前面在RefBase::incStrong函數里的refs->addWeakRef函數調用語句的,在Release版本中,這也是一個空實現函數,真正實現強引用計數減1的操作下面的refs->decWeak函數,weakref_impl類沒有實現自己的decWeak函數,它繼承了weakref_type類的decWeak函數:
? ? 這里又一次調用了weakref_impl對象的removeWeakRef函數,這也是和RefBase::weakref_type::incWeak函數里面的impl->addWeakRef語句所對應的,實現弱引用計數減1的操作是下面語句:const?int32_t?c?=?android_atomic_dec(&impl->mWeak); ?
?減1前如果發現不等于1,那么就什么也不用做就返回了,如果發現等于1,就說明當前對象的弱引用計數值為0了,這時候,就要看看是否要delete這個對象了:
??如果目標對象的生命周期是不受弱引用計數控制的,就執行下面語句:
? ? ?這個代碼段是什么意思呢?這里是減少對象的弱引用計數的地方,如果調用到這里,那么就說明前面一定有增加過此對象的弱引用計數,而增加對象的弱引用計數有兩種場景的,一種場景是增加對象的強引用計數的時候,會同時增加對象的弱引用計數,另一種場景是當我們使用一個弱指針來指向對象時,在弱指針對象的構造函數里面,也會增加對象的弱引用計數,不過這時候,就只是增加對象的弱引用計數了,并沒有同時增加對象的強引用計數。因此,這里在減少對象的弱引用計數時,就要分兩種情況來考慮。
?
? ? ? ? 如果是前一種場景,這里的impl->mStrong就必然等于0,而不會等于INITIAL_STRONG_VALUE值,因此,這里就不需要delete目標對象了(impl->mBase),因為前面的RefBase::decStrong函數會負責delete這個對象。這里唯一需要做的就是把weakref_impl對象delete掉,但是,為什么要在這里delete這個weakref_impl對象呢?這里的weakref_impl對象是在RefBase的構造函數里面new出來的,理論上說應該在在RefBase的析構函數里delete掉這個weakref_impl對象的。在RefBase的析構函數里面,的確是會做這件事情:
? ?但是不要忘記,在這個場景下,目標對象是前面的RefBase::decStrong函數delete掉的,這時候目標對象就會被析構,但是它的弱引用計數值尚未執行減1操作,因此,這里的mRefs->mWeak == 0條件就不成立,于是就不會delete這個weakref_impl對象,因此,就延遲到執行這里decWeak函數時再執行。?
如果是后一種情景,這里的impl->mStrong值就等于INITIAL_STRONG_VALUE了,這時候由于沒有地方會負責delete目標對象,因此,就需要把目標對象(imp->mBase)delete掉了,否則就會造成內存泄漏。在delete這個目標對象的時候,就會執行RefBase類的析構函數,這時候目標對象的弱引用計數等于0,于是,就會把weakref_impl對象也一起delete掉了。
本文轉自 Luoshengyang 51CTO博客,原文鏈接:http://blog.51cto.com/shyluo/966562,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析(3)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于PN短码的理解
- 下一篇: CCNA课堂练习:OSPF的介绍及配置