Android系統的運行時庫層代碼是用C++來編寫的,用C++來寫代碼最容易出錯的地方就是指針了,一旦使用不當,輕則造成內存泄漏,重則造成系統 崩潰。不過系統為我們提供了智能指針,避免出現上述問題,本文將系統地分析Android系統智能指針(輕量級指針、強指針和弱指針)的實現原理。

        在使用C++來編寫代碼的過程中,指針使用不當造成內存泄漏一般就是因為new了一個對象並且使用完之後,忘記了delete這個對象,而造成系統崩潰 一般就是因為一個地方delete了這個對象之後,其它地方還在繼續使原來指向這個對象的指針。為了避免出現上述問題,一般的做法就是使用引用計數的方 法,每當有一個指針指向了一個new出來的對象時,就對這個對象的引用計數增加1,每當有一個指針不再使用這個對象時,就對這個對象的引用計數減少1,每 次減1之後,如果發現引用計數值為0時,那麼,就要delete這個對象了,這樣就避免了忘記delete對象或者這個對象被delete之後其它地方還 在使用的問題了。但是,如何實現這個對象的引用計數呢?肯定不是由開發人員來手動地維護了,要開發人員時刻記住什麼時候該對這個對象的引用計數加1,什麼 時候該對這個對象的引用計數減1,一來是不方便開發,二來是不可靠,一不小心哪裏多加了一個1或者多減了一個1,就會造成災難性的後果。這時候,智能指針 就粉墨登場了。首先,智能指針是一個對象,不過這個對象代表的是另外一個真實使用的對象,當智能指針指向實際對象的時候,就是智能指針對象創建的時候,當 智能指針不再指向實際對象的時候,就是智能指針對象銷燬的時候,我們知道,在C++中,對象的創建和銷燬時會分別自動地調用對象的構造函數和析構函數,這 樣,負責對真實對象的引用計數加1和減1的工作就落實到智能指針對象的構造函數和析構函數的身上了,這也是為什麼稱這個指針對象為智能指針的原因。

        在計算機科學領域中,提供垃圾收集(Garbage Collection)功能的系統框架,即提供對象託管功能的系統框架,例如Java應用程序框架,也是採用上述的引用計數技術方案來實現的,然而,簡單 的引用計數技術不能處理系統中對象間循環引用的情況。考慮這樣的一個場景,系統中有兩個對象A和B,在對象A的內部引用了對象B,而在對象B的內部也引用 了對象A。當兩個對象A和B都不再使用時,垃圾收集系統會發現無法回收這兩個對象的所佔據的內存的,因為系統一次只能收集一個對象,而無論系統決定要收回 對象A還是要收回對象B時,都會發現這個對象被其它的對象所引用,因而就都回收不了,這樣就造成了內存泄漏。這樣,就要採取另外的一種引用計數技術了,即 對象的引用計數同時存在強引用和弱引用兩種計數,例如,Apple公司提出的Cocoa框 架,當父對象要引用子對象時,就對子對象使用強引用計數技術,而當子對象要引用父對象時,就對父對象使用弱引用計數技術,而當垃圾收集系統執行對象回收工 作時,只要發現對象的強引用計數為0,而不管它的弱引用計數是否為0,都可以回收這個對象,但是,如果我們只對一個對象持有弱引用計數,當我們要使用這個 對象時,就不直接使用了,必須要把這個弱引用升級成為強引用時,才能使用這個對象,在轉換的過程中,如果對象已經不存在,那麼轉換就失敗了,這時候就説明 這個對象已經被銷燬了,不能再使用了。

       瞭解了這些背景知識後,我們就可以進一步學習Android系統的智能指針的實現原理了。Android系統提供了強大的智能指針技術供我們使用,這些智 能指針實現方案既包括簡單的引用計數技術,也包括了複雜的引用計數技術,即對象既有強引用計數,也有弱引用計數,對應地,這三種智能指針分別就稱為輕量級 指針(Light Pointer)、強指針(Strong Pointer)和弱指針(Weak Pointer)。無論是輕量級指針,還是強指針和弱指針,它們的實現框架都是一致的,即由對象本身來提供引用計數器,但是它不會去維護這個引用計數器的 值,而是由智能指針來維護,就好比是對象提供素材,但是具體怎麼去使用這些素材,就交給智能指針來處理了。由於不管是什麼類型的對象,它都需要提供引用計 數器這個素材,在C++中,我們就可以把這個引用計數器素材定義為一個公共類,這個類只有一個成員變量,那就是引用計數成員變量,其它提供智能指針引用的 對象,都必須從這個公共類繼承下來,這樣,這些不同的對象就天然地提供了引用計數器給智能指針使用了。總的來説就是我們在實現智能指會的過程中,第一是要 定義一個負責提供引用計數器的公共類,第二是我們要實現相應的智能指針對象類,後面我們會看到這種方案是怎麼樣實現的。

        接下來,我們就先介紹輕量級指針的實現原理,然後再接着介紹強指針和弱指針的實現原理。

        1. 輕量級指針

        先來看一下實現引用計數的類LightRefBase,它定義在frameworks/base/include/utils/RefBase.h文件中:



[cpp] view plain copy


1. template <class
2. class
3. {  
4. public:  
5. inline
6. inline void incStrong(const void* id) const
7.         android_atomic_inc(&mCount);  
8.     }  
9. inline void decStrong(const void* id) const
10. if
11. delete static_cast<const T*>(this);  
12.         }  
13.     }  
14. //! DEBUGGING ONLY: Get current strong ref count.
15. inline int32_t getStrongCount() const
16. return
17.     }  
18.   
19. protected:  
20. inline
21.   
22. private:  
23. mutable volatile
24. };

         這個類很簡單,它只一個成員變量mCount,這就是引用計數器了,它的初始化值為0,另外,這個類還提供兩個成員函數incStrong和 decStrong來維護引用計數器的值,這兩個函數就是提供給智能指針來調用的了,這裏要注意的是,在decStrong函數中,如果當前引用計數值為 1,那麼當減1後就會變成0,於是就會delete這個對象。


         前面説過,要實現自動引用計數,除了要有提供引用計數器的基類外,還需要有智能指針類。在Android系統中,配合LightRefBase引用計數使 用的智能指針類便是sp了,它也是定義在frameworks/base/include/utils/RefBase.h文件中:



[cpp] view plain copy

1. template <typename
2. class
3. {  
4. public:  
5. typedef typename
6.   
7. inline
8.   
9.     sp(T* other);  
10. const
11. template<typename
12. template<typename U> sp(const
13.   
14.     ~sp();  
15.   
16. // Assignment
17.   
18.     sp& operator = (T* other);  
19. const
20.   
21. template<typename U> sp& operator = (const
22. template<typename
23.   
24. //! Special optimization for use by ProcessState (and nobody else).
25. void
26.   
27. // Reset
28.   
29. void
30.   
31. // Accessors
32.   
33. inline  T&      operator* () const  { return
34. inline  T*      operator-> () const { return
35. inline  T*      get() const         { return
36.   
37. // Operators
38.   
39.     COMPARE(==)  
40.         COMPARE(!=)  
41.         COMPARE(>)  
42.         COMPARE(<)  
43.         COMPARE(<=)  
44.         COMPARE(>=)  
45.   
46. private:  
47. template<typename Y> friend class
48. template<typename Y> friend class
49.   
50. // Optimization for wp::promote().
51.     sp(T* p, weakref_type* refs);  
52.   
53.     T*              m_ptr;  
54. };

        這個類的內容比較多,但是這裏我們只關注它的成員變量m_ptr、構造函數和析構函數。不難看出,成員變量m_ptr就是指向真正的對象了,它是在構造函數裏面初始化的。接下來我們就再看一下它的兩個構造函數,一個是普通構造函數,一個拷貝構造函數:


[cpp] view plain copy



1. template<typename
2. sp<T>::sp(T* other)  
3.     : m_ptr(other)  
4. {  
5. if (other) other->incStrong(this);  
6. }  
7.   
8. template<typename
9. sp<T>::sp(const
10.     : m_ptr(other.m_ptr)  
11. {  
12. if (m_ptr) m_ptr->incStrong(this);  
13. }

        這兩個構造函數都會首先初始化成員變量m_ptr,然後再調用m_ptr的incStrong函數來增加對象的引用計數,在我們這個場景中,就是調用LightRefBase類的incStrong函數了。


        最後,看一下析構函數:



[cpp] view plain copy


1. template<typename
2. sp<T>::~sp()  
3. {  
4. if (m_ptr) m_ptr->decStrong(this);  
5. }

        析構函數也很簡單,只是調用m_ptr的成員函數decStrong來減少對象的引用計數值,這裏就是調用LightRefBase類的decStrong函數了,前面我們看到,當這個引用計數減1後變成0時,就會自動delete這個對象了。


        輕量級智能指針的實現原理大概就是這樣了,比較簡單,下面我們再用一個例子來説明它的用法。

        2. 輕量級指針的用法

        參考在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序一文,我們在external目錄下建立一個C++工程目錄lightpointer,它裏面有兩個文件,一個lightpointer.cpp文件,另外一個是Android.mk文件。

        源文件lightpointer.cpp的內容如下:



[cpp] view plain copy


1. #include <stdio.h>
2. #include <utils/RefBase.h>
3.   
4. using namespace
5.   
6. class LightClass : public
7. {  
8. public:  
9.         LightClass()  
10.         {  
11. "Construct LightClass Object.");  
12.         }  
13.   
14. virtual
15.         {  
16. "Destory LightClass Object.");  
17.         }  
18. };  
19.   
20. int main(int argc, char** argv)  
21. {  
22. new
23.         sp<LightClass> lpOut = pLightClass;  
24.   
25. "Light Ref Count: %d.\n", pLightClass->getStrongCount());  
26.   
27.         {  
28.                 sp<LightClass> lpInner = lpOut;  
29.   
30. "Light Ref Count: %d.\n", pLightClass->getStrongCount());  
31.         }  
32.   
33. "Light Ref Count: %d.\n", pLightClass->getStrongCount());  
34.   
35. return
36. }

        我們創建一個自己的類LightClass,繼承了LightRefBase模板類,這樣類LightClass就具有引用計數的功能了。在main函 數裏面,我們首先new一個LightClass對象,然後把這個對象賦值給智能指針lpOut,這時候通過一個printf語句來將當前對象的引用計數 值打印出來,從前面的分析可以看出,如果一切正常的話,這裏打印出來的引用計數值為1。接着,我們又在兩個大括號裏面定義了另外一個智能指針 lpInner,它通過lpOut間接地指向了前面我們所創建的對象,這時候再次將當前對象的引用計數值打印出來,從前面 的分析也可以看出,如果一切正常的話,這裏打印出來的引用計數值應該為2。程序繼承往下執行,當出了大括號的範圍的時候,智能指針對象lpInner就被 析構了,從前面的分析可以知道,智能指針在析構的時候,會減少當前對象的引用計數值,因此,最後一個printf語句打印出來的引用計數器值應該為1。當 main函數執行完畢後,智能指針lpOut也會被析構,被析構時,它會再次減少當前對象的引用計數,這時候,對象的引用計數值就為0了,於是,它就會被 delete了。


        編譯腳本文件Android.mk的內容如下:



[plain] view plain copy




1. LOCAL_PATH := $(call my-dir)  
2. include $(CLEAR_VARS)  
3. LOCAL_MODULE_TAGS := optional  
4. LOCAL_MODULE := lightpointer  
5. LOCAL_SRC_FILES := lightpointer.cpp  
6. LOCAL_SHARED_LIBRARIES := \  
7.         libcutils \  
8.         libutils  
9. include $(BUILD_EXECUTABLE)

        最後,我們參照

如何單獨編譯Android源代碼中的模塊一文,使用mmm命令對工程進行編譯:


[plain] view plain copy




1. USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer

        編譯之後,就可以打包了:


[plain] view plain copy


1. USER-NAME@MACHINE-NAME:~/Android$ make snod

        最後得到可執行程序lightpointer就位於設備上的/system/bin/目錄下。啓動模擬器,通過adb shell命令進入到模擬器終端,進入到/system/bin/目錄,執行lightpointer可執行程序,驗證程序是否按照我們設計的邏輯運行:


[plain] view plain copy


1. USER-NAME@MACHINE-NAME:~/Android$ adb shell  
2. root@android:/ # cd system/bin/          
3. root@android:/system/bin # ./lightpointer                                        
4. Construct LightClass Object.  
5. Light Ref Count: 1.  
6. Light Ref Count: 2.  
7. Light Ref Count: 1.  
8. Destory LightClass Object.

       這裏可以看出,程序一切都是按照我們的設計來運行,這也驗證了我們上面分析的輕量級智能指針的實現原理。

       3. 強指針

       強指針所使用的引用計數類為RefBase,它LightRefBase類要複雜多了,所以才稱後者為輕量級的引用計數基類吧。我們先來看看 RefBase類的實現,它定義在frameworks/base/include/utils/RefBase.h文件中:



[cpp] view plain copy


1. class
2. {  
3. public:  
4. void            incStrong(const void* id) const;  
5. void            decStrong(const void* id) const;  
6.   
7. void            forceIncStrong(const void* id) const;  
8.   
9. //! DEBUGGING ONLY: Get current strong ref count.
10. const;  
11.   
12. class
13.     {  
14. public:  
15. const;  
16.   
17. void                incWeak(const void* id);  
18. void                decWeak(const void* id);  
19.   
20. bool                attemptIncStrong(const void* id);  
21.   
22. //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
23. bool                attemptIncWeak(const void* id);  
24.   
25. //! DEBUGGING ONLY: Get current weak ref count.
26. const;  
27.   
28. //! DEBUGGING ONLY: Print references held on object.
29. void                printRefs() const;  
30.   
31. //! DEBUGGING ONLY: Enable tracking for this object.
32. // enable -- enable/disable tracking
33. // retain -- when tracking is enable, if true, then we save a stack trace
34. //           for each reference and dereference; when retain == false, we
35. //           match up references and dereferences and keep only the 
36. //           outstanding ones.
37.   
38. void                trackMe(bool enable, bool
39.     };  
40.   
41. const void* id) const;  
42.   
43. const;  
44.   
45. //! DEBUGGING ONLY: Print references held on object.
46. inline  void            printRefs() const
47.   
48. //! DEBUGGING ONLY: Enable tracking of object.
49. inline  void            trackMe(bool enable, bool
50.     {  
51.         getWeakRefs()->trackMe(enable, retain);  
52.     }  
53.   
54. protected:  
55.     RefBase();  
56. virtual
57.   
58. //! Flags for extendObjectLifetime()
59. enum
60.         OBJECT_LIFETIME_WEAK    = 0x0001,  
61.         OBJECT_LIFETIME_FOREVER = 0x0003  
62.     };  
63.   
64. void
65.   
66. //! Flags for onIncStrongAttempted()
67. enum
68.         FIRST_INC_STRONG = 0x0001  
69.     };  
70.   
71. virtual void
72. virtual void            onLastStrongRef(const void* id);  
73. virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);  
74. virtual void            onLastWeakRef(const void* id);  
75.   
76. private:  
77. friend class
78. class
79.   
80. const
81. const
82.   
83. const
84. };

        RefBase類和LightRefBase類一樣,提供了incStrong和decStrong成員函數來操作它的引用計數器;而RefBase類 與LightRefBase類最大的區別是,它不像LightRefBase類一樣直接提供一個整型值(mutable volatile int32_t mCount)來維護對象的引用計數,前面我們説過,複雜的引用計數技術同時支持強引用計數和弱引用計數,在RefBase類中,這兩種計數功能是通過其 成員變量mRefs來提供的。


        RefBase類的成員變量mRefs的類型為weakref_impl指針,它實現在frameworks/base/libs/utils/RefBase.cpp文件中:



[cpp] view plain copy



1. class RefBase::weakref_impl : public
2. {  
3. public:  
4. volatile
5. volatile
6. const
7. volatile
8.   
9.   
10. #if !DEBUG_REFS
11.   
12.     weakref_impl(RefBase* base)  
13.         : mStrong(INITIAL_STRONG_VALUE)  
14.         , mWeak(0)  
15.         , mBase(base)  
16.         , mFlags(0)  
17.     {  
18.     }  
19.   
20. void addStrongRef(const void* /*id*/) { }  
21. void removeStrongRef(const void* /*id*/) { }  
22. void addWeakRef(const void* /*id*/) { }  
23. void removeWeakRef(const void* /*id*/) { }  
24. void printRefs() const
25. void trackMe(bool, bool) { }  
26.   
27. #else
28.     weakref_impl(RefBase* base)  
29.         : mStrong(INITIAL_STRONG_VALUE)  
30.         , mWeak(0)  
31.         , mBase(base)  
32.         , mFlags(0)  
33.         , mStrongRefs(NULL)  
34.         , mWeakRefs(NULL)  
35.         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)  
36. false)  
37.     {  
38. //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
39.     }  
40.   
41.     ~weakref_impl()  
42.     {  
43. "Strong references remain!");  
44. "Weak references remain!");  
45.     }  
46.   
47. void addStrongRef(const void* id)  
48.     {  
49.         addRef(&mStrongRefs, id, mStrong);  
50.     }  
51.   
52. void removeStrongRef(const void* id)  
53.     {  
54. if
55.             removeRef(&mStrongRefs, id);  
56. else
57.             addRef(&mStrongRefs, id, -mStrong);  
58.     }  
59.   
60. void addWeakRef(const void* id)  
61.     {  
62.         addRef(&mWeakRefs, id, mWeak);  
63.     }  
64. void removeWeakRef(const void* id)  
65.     {  
66. if
67.             removeRef(&mWeakRefs, id);  
68. else
69.             addRef(&mWeakRefs, id, -mWeak);  
70.     }  
71.   
72. void trackMe(bool track, bool
73.     {  
74.         mTrackEnabled = track;  
75.         mRetain = retain;  
76.     }  
77.   
78.     ......  
79.   
80. private:  
81. struct
82.     {  
83.         ref_entry* next;  
84. const void* id;  
85. #if DEBUG_REFS_CALLSTACK_ENABLED
86.         CallStack stack;  
87. #endif
88.         int32_t ref;  
89.     };  
90.   
91. void addRef(ref_entry** refs, const void* id, int32_t mRef)  
92.     {  
93. if
94.             AutoMutex _l(mMutex);  
95. new
96. // Reference count at the time of the snapshot, but before the
97. // update.  Positive value means we increment, negative--we
98. // decrement the reference count.
99.             ref->ref = mRef;  
100.             ref->id = id;  
101. #if DEBUG_REFS_CALLSTACK_ENABLED
102.             ref->stack.update(2);  
103. #endif
104.   
105.             ref->next = *refs;  
106.             *refs = ref;  
107.         }  
108.     }  
109.   
110. void removeRef(ref_entry** refs, const void* id)  
111.     {  
112. if
113.             AutoMutex _l(mMutex);  
114.   
115.             ref_entry* ref = *refs;  
116. while
117. if
118.                     *refs = ref->next;  
119. delete
120. return;  
121.                 }  
122.   
123.                 refs = &ref->next;  
124.                 ref = *refs;  
125.             }  
126.   
127. "RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",  
128. this);  
129.         }  
130.     }  
131.   
132.     ......  
133.   
134.     Mutex mMutex;  
135.     ref_entry* mStrongRefs;  
136.     ref_entry* mWeakRefs;  
137.   
138. bool
139. // Collect stack traces on addref and removeref, instead of deleting the stack references
140. // on removeref that match the address ones.
141. bool
142.   
143.     ......  
144. #endif
145. };

        這個類看起來實現得很複雜,其實不然,這個類的實現可以分成兩部分:


[cpp] view plain copy


1. #if !DEBUG_REFS
2.   
3. ......  
4.   
5. #else

        編譯指令之間的這部分源代碼是Release版本的源代碼,它的成員函數都是空實現;


[cpp] view plain copy


1. #else 
2.   
3. ......  
4.   
5. #endif

        編譯指令之間的部分源代碼是Debug版本的源代碼,它的成員函數都是有實現的,實現這些函數的目的都是為了方便開發人員調試引用計數用的,除此之外,還在內部實現了一個結構體ref_entry:


[cpp] view plain copy


1. struct
2. {  
3.     ref_entry* next;  
4. const void* id;  
5. #if DEBUG_REFS_CALLSTACK_ENABLED
6.     CallStack stack;  
7. #endif
8.     int32_t ref;  
9. };

        這個結構體也是為了方便調試而使用的,我們可以不關注這部分用於調試的代碼。


        總的來説,weakref_impl類只要提供了以下四個成員變量來維護對象的引用計數:



[cpp] view plain copy


1. volatile
2. volatile
3. RefBase* const
4. volatile

        其中mStrong和mWeak分別表示對象的強引用計數和弱引用計數;RefBase類包含了一個weakref_impl類指針mRefs,而這裏 的weakref_impl類也有一個成員變量mBase來指向它的宿主類RefBase;mFlags是一個標誌位,它指示了維護對象引用計數所使用的 策略,後面我們將會分析到,它的取值為0,或者以下的枚舉值:


[cpp] view plain copy


1. //! Flags for extendObjectLifetime()
2. enum
3.         OBJECT_LIFETIME_WEAK    = 0x0001,  
4.         OBJECT_LIFETIME_FOREVER = 0x0003  
5.     };

        這裏我們還需要注意的一點的是,從weakref_impl的類名來看,它應該是一個實現類,那麼,就必然有一個對應的接口類,這個對應的接口類的就是 RefBase類內部定義的weakref_type類了,這是一種把類的實現與接口定義分離的設計方法。學習過設計模式的讀者應該知道,在設計模式裏 面,非常強調類的接口定義和類的實現分離,以便利於後續擴展和維護,這裏就是用到了這種設計思想。


        説了這多,RefBase類給人的感覺還是挺複雜的,不要緊,我們一步步來,先通過下面這個圖來梳理一下這些類之間的關係:

        從這個類圖可以看出,每一個RefBase對象包含了一個weakref_impl對象,而weakref_impl對象實現了 weakref_type接口,同時它可以包含多個ref_entry對象,前面説過,ref_entry是調試用的一個結構體,實際使用中可以不關注。

        提供引用計數器的類RefBase我們就暫時介紹到這裏,後面我們再結合智能指針類一起分析,現在先來看看強指針類和弱指針類的定義。強指針類的定義我 們在前面介紹輕量級指針的時候已經見到了,就是sp類了,這裏就不再把它的代碼列出來了。我們來看看它的構造函數的實現:



[cpp] view plain copy


1. template<typename
2. sp<T>::sp(T* other)  
3.     : m_ptr(other)  
4. {  
5. if (other) other->incStrong(this);  
6. }


        這裏傳進來的參數other一定是繼承於RefBase類的,因此,在函數的內部,它調用的是RefBase類的incStrong函數,它定義在frameworks/base/libs/utils/RefBase.cpp文件中:



[cpp] view plain copy


1. void RefBase::incStrong(const void* id) const
2. {  
3. const
4.     refs->addWeakRef(id);  
5.     refs->incWeak(id);  
6.     refs->addStrongRef(id);   
7.   
8. const
9. "incStrong() called on %p after last strong ref", refs);  
10.   
11.     #if PRINT_REFS 
12. "incStrong of %p from %p: cnt=%d\n", this, id, c);  
13.     #endif 
14.   
15. if
16. return;   
17.     }   
18.   
19.     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);   
20. const_cast<RefBase*>(this)->onFirstRef();  
21. }

        成員變量mRefs是在RefBase類的構造函數中創建的:


[cpp] view plain copy


1. RefBase::RefBase()  
2. new weakref_impl(this))  
3. {  
4. //    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
5. }

        在這個incStrong函數中,主要做了三件事情:


        一是增加弱引用計數:



[cpp] view plain copy


1. refs->addWeakRef(id);  
2. refs->incWeak(id);

        二是增加強引用計數:


[cpp] view plain copy


1. refs->addStrongRef(id);  
2. const

        三是如果發現是首次調用這個對象的incStrong函數,就會調用一個這個對象的onFirstRef函數,讓對象有機會在對象被首次引用時做一些處理邏輯:


[cpp] view plain copy



1. if
2. return;  
3. }  
4.   
5. android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);  
6. const_cast<RefBase*>(this)->onFirstRef();


       這裏的c返回的是refs->mStrong加1前的值,如果發現等於INITIAL_STRONG_VALUE,就説明這個對象的強引用計數是第 一次被增加,因此,refs->mStrong就是初始化為INITIAL_STRONG_VALUE的,它的值為:


[cpp] view plain copy


1. #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函數:



[cpp] view plain copy


1. void RefBase::weakref_type::incWeak(const void* id)  
2. {  
3. const impl = static_cast<weakref_impl*>(this);  
4.     impl->addWeakRef(id);  
5. const
6. "incWeak called on %p after last weak ref", this);  
7. }

       增加弱引用計數是下面語句執行的:


[cpp] view plain copy


1. const

        但是前面為什麼又調用了一次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。

        再來看看強指針類的析構函數的實現:

 



[cpp] view plain copy


1. template<typename
2. sp<T>::~sp()  
3. {  
4. if (m_ptr) m_ptr->decStrong(this);  
5. }

       同樣,這裏的m_ptr指向的目標對象一定是繼承了RefBase類的,因此,這裏調用的是

RefBase類的decStrong函數,這也是定義在frameworks/base/libs/utils/RefBase.cpp文件中:


 



[cpp] view plain copy


1. void RefBase::decStrong(const void* id) const
2. {  
3. const
4.     refs->removeStrongRef(id);  
5. const
6. #if PRINT_REFS
7. "decStrong of %p from %p: cnt=%d\n", this, id, c);  
8. #endif
9. "decStrong() called on %p too many times", refs);  
10. if
11. const_cast<RefBase*>(this)->onLastStrongRef(id);  
12. if
13. delete this;  
14.         }  
15.     }  
16.     refs->removeWeakRef(id);  
17.     refs->decWeak(id);  
18. }

        這裏的refs->removeStrongRef函數調用語句是對應前面在RefBase::incStrong函數裏的 refs->addStrongRef函數調用語句的,在Release版本中,這也是一個空實現函數,真正實現強引用計數減1的操作是下面語句:


[cpp] view plain copy




1. const

        如果發現減1前,此對象的強引用計數為1,就説明從此以後,就再沒有地方引用這個目標對象了,這時候,就要看看是否要delete這個目標對象了:


 



[cpp] view plain copy

1. if
2. const_cast<RefBase*>(this)->onLastStrongRef(id);  
3. if
4. delete this;  
5.     }  
6. }

        在強引用計數為0的情況下,如果對象的標誌位OBJECT_LIFETIME_WEAK被設置了,就説明這個對象的生命週期是受弱引用計數所控制的,因此,這時候就不能delete對象,要等到弱引用計數也為0的情況下,才能delete這個對象。


RefBase::incStrong函數裏的refs->addWeakRef函數調用語句的,在Release版本中,這也是一個空實現函數,真正實現強引用計數減1的操作下面的refs->decWeak函數,weakref_impl類沒有實現自己的decWeak函數,它繼承了weakref_type類的decWeak函數:

 



[cpp] view plain copy


1. void RefBase::weakref_type::decWeak(const void* id)  
2. {  
3. const impl = static_cast<weakref_impl*>(this);  
4.     impl->removeWeakRef(id);  
5. const
6. "decWeak called on %p too many times", this);  
7. if (c != 1) return;  
8.   
9. if
10. if
11. delete
12. else
13. //            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
14. delete
15.         }  
16. else
17.         impl->mBase->onLastWeakRef(id);  
18. if
19. delete
20.         }  
21.     }  
22. }

       這裏又一次調用了weakref_impl對象的removeWeakRef函數,這也是和 RefBase::weakref_type::incWeak函數裏面的impl->addWeakRef語句所對應的,實現弱引用計數減1的操 作是下面語句:


 



[cpp] view plain copy



  1. const

       減1前如果發現不等於1,那麼就什麼也不用做就返回了,如果發現等於1,就説明當前對象的弱引用計數值為0了,這時候,就要看看是否要delete這個對象了:


 



[cpp] view plain copy


1. if
2. if
3. delete
4. else
5. //      LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
6. delete
7.     }  
8. } else
9.     impl->mBase->onLastWeakRef(id);  
10. if
11. delete
12.     }  
13. }

        如果目標對象的生命週期是不受弱引用計數控制的,就執行下面語句:


 



[cpp] view plain copy



1. if
2. delete
3. else
4. //  LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
5. delete
6. }

        這個代碼段是什麼意思呢?這裏是減少對象的弱引用計數的地方,如果調用到這裏,那麼就説明前面一定有增加過此對象的弱引用計數,而增加對象的弱引用計數 有兩種場景的,一種場景是增加對象的強引用計數的時候,會同時增加對象的弱引用計數,另一種場景是當我們使用一個弱指針來指向對象時,在弱指針對象的構造 函數裏面,也會增加對象的弱引用計數,不過這時候,就只是增加對象的弱引用計數了,並沒有同時增加對象的強引用計數。因此,這裏在減少對象的弱引用計數 時,就要分兩種情況來考慮。


        如果是前一種場景,這裏的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的析構函數裏面,的確是會做這件事情:

 



[cpp] view plain copy


1. RefBase::~RefBase()  
2. {  
3. //    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
4. if
5. //        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
6. delete
7.     }  
8. }


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掉了。

        回到外層的if語句中,如果目標對象的生命週期是受弱引用計數控制的,就執行下面語句:

 



[cpp] view plain copy


1. impl->mBase->onLastWeakRef(id);  
2. if
3. delete
4. }

        理論上説,如果目標對象的生命週期是受

弱 引用計數控制的,那麼當強引用計數和弱引用計數都為0的時候,這時候就應該delete目標對象了,但是這裏還有另外一層控制,我們可以設置目標對象的標 志值為OBJECT_LIFETIME_FOREVER,即目標對象的生命週期完全不受強引用計數和弱引用計數控制,在這種情況下,即使目標對象的強引用 計數和弱引用計數都同時為0,這裏也不能delete這個目標對象,那麼,由誰來delete掉呢?當然是誰new出來的,就誰來delete掉了,這時 候智能指針就完全退化為普通指針了,這裏的智能指針設計的非常強大。


        分析到這裏,有必要小結一下:

        A. 如果對象的標誌位被設置為0,那麼只要發現對象的強引用計數值為0,那就會自動delete掉這個對象;

        B. 如果對象的標誌位被設置為OBJECT_LIFETIME_WEAK,那麼只有當對象的強引用計數和弱引用計數都為0的時候,才會自動delete掉這個對象;

OBJECT_LIFETIME_FOREVER,那麼對象就永遠不會自動被delete掉,誰new出來的對象誰來delete掉。

        到了這裏,強指針就分析完成了,最後來分析弱指針。

        4. 弱指針

        弱指針所使用的引用計數類與強指針一樣,都是RefBase類,因此,這裏就不再重複介紹了,我們直接來弱指針的實現,它定義在frameworks/base/include/utils/RefBase.h文件中:



[cpp] view plain copy


1. template <typename
2. class
3. {  
4. public:  
5. typedef typename
6.   
7. inline
8.   
9.     wp(T* other);  
10. const
11. const
12. template<typename
13. template<typename U> wp(const
14. template<typename U> wp(const
15.   
16.     ~wp();  
17.   
18. // Assignment
19.   
20.     wp& operator = (T* other);  
21. const
22. const
23.   
24. template<typename
25. template<typename U> wp& operator = (const
26. template<typename U> wp& operator = (const
27.   
28. void
29.   
30. // promotion to sp
31.   
32. const;  
33.   
34. // Reset
35.   
36. void
37.   
38. // Accessors
39.   
40. inline  weakref_type* get_refs() const { return
41.   
42. inline  T* unsafe_get() const { return
43.   
44. // Operators
45.   
46.     COMPARE_WEAK(==)  
47.         COMPARE_WEAK(!=)  
48.         COMPARE_WEAK(>)  
49.         COMPARE_WEAK(<)  
50.         COMPARE_WEAK(<=)  
51.         COMPARE_WEAK(>=)  
52.   
53. inline bool operator == (const wp<T>& o) const
54. return
55.     }  
56. template<typename
57. inline bool operator == (const wp<U>& o) const
58. return
59.     }  
60.   
61. inline bool operator > (const wp<T>& o) const
62. return
63.     }  
64. template<typename
65. inline bool operator > (const wp<U>& o) const
66. return
67.     }  
68.   
69. inline bool operator < (const wp<T>& o) const
70. return
71.     }  
72. template<typename
73. inline bool operator < (const wp<U>& o) const
74. return
75.     }  
76. inline bool operator != (const wp<T>& o) const { return
77. template<typename U> inline bool operator != (const wp<U>& o) const { return
78. inline bool operator <= (const wp<T>& o) const { return
79. template<typename U> inline bool operator <= (const wp<U>& o) const { return
80. inline bool operator >= (const wp<T>& o) const { return
81. template<typename U> inline bool operator >= (const wp<U>& o) const { return
82.   
83. private:  
84. template<typename Y> friend class
85. template<typename Y> friend class
86.   
87.     T*              m_ptr;  
88.     weakref_type*   m_refs;  
89. };

        與強指針類相比,它們都有一個成員變量m_ptr指向目標對象,但是弱指針還有一個額外的成員變量m_refs,它的類型是weakref_type指 針,下面我們分析弱指針的構造函數時再看看它是如果初始化的。這裏我們需要關注的仍然是弱指針的構造函數和析構函數。


        先來看構造函數:



[cpp] view plain copy


1. template<typename
2. wp<T>::wp(T* other)  
3.     : m_ptr(other)  
4. {  
5. if (other) m_refs = other->createWeak(this);  
6. }

        這裏的參數other一定是繼承了RefBase類,因此,這裏調用了RefBase類的createWeak函數,它定義在frameworks/base/libs/utils/RefBase.cpp文件中:


 



[cpp] view plain copy


1. RefBase::weakref_type* RefBase::createWeak(const void* id) const
2. {  
3.     mRefs->incWeak(id);  
4. return
5. }

        這裏的成員變量mRefs的類型為weakref_impl指針,

weakref_impl類的incWeak函數我們在前面已經看過了,它的作用就是增加對象的弱引用計數。函數最後返回mRefs,於是,弱指針對象的成員變量m_refs就指向目標對象的weakref_impl對象了。


        再來看析構函數:



[cpp] view plain copy



1. template<typename
2. wp<T>::~wp()  
3. {  
4. if (m_ptr) m_refs->decWeak(this);  
5. }

        這裏,弱指針在析構的時候,與強指針析構不一樣,它直接就調用目標對象的weakref_impl對象的decWeak函數來減少弱引用計數了,當弱引用計數為0的時候,就會根據在目標對象的標誌位(0、

OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER)來決定是否要delete目標對象,前面我們已經介紹過了,這裏就不再介紹了。


        分析到這裏,弱指針還沒介紹完,它最重要的特性我們還沒有分析到。前面我們説過,弱指針的最大特點是它不能直接操作目標對象,這是怎麼樣做到的呢?秘密 就在於弱指針類沒有重載*和->操作符號,而強指針重載了這兩個操作符號。但是,如果我們要操作目標對象,應該怎麼辦呢,這就要把弱指針升級為強指 針了:

 



[cpp] view plain copy



1. template<typename
2. sp<T> wp<T>::promote() const
3. {  
4. return
5. }

        升級的方式就使用成員變量m_ptr和m_refs來構造一個強指針sp,這裏的m_ptr為指目標對象的一個指針,而m_refs則是指向目標對象裏面的weakref_impl對象。


        我們再來看看這個強指針的構造過程:



[cpp] view plain copy



1. template<typename
2. sp<T>::sp(T* p, weakref_type* refs)  
3. this)) ? p : 0)  
4. {  
5. }

        主要就是初始化指向目標對象的成員變量m_ptr了,如果目標對象還存在,這個m_ptr就指向目標對象,如果目標對象已經不存在,m_ptr就為NULL,升級成功與否就要看refs->attemptIncStrong函數的返回結果了:


[cpp] view plain copy


1. bool RefBase::weakref_type::attemptIncStrong(const void* id)  
2. {  
3.     incWeak(id);  
4.   
5. const impl = static_cast<weakref_impl*>(this);  
6.   
7.     int32_t curCount = impl->mStrong;  
8. "attemptIncStrong called on %p after underflow",  
9. this);  
10. while
11. if
12. break;  
13.         }  
14.         curCount = impl->mStrong;  
15.     }  
16.   
17. if
18. bool
19. if
20. // Attempting to acquire first strong reference...  this is allowed
21. // if the object does NOT have a longer lifetime (meaning the
22. // implementation doesn't need to see this), or if the implementation
23. // allows it to happen.
24.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK  
25.                 || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
26. else
27. // Attempting to revive the object...  this is allowed
28. // if the object DOES have a longer lifetime (so we can safely
29. // call the object with only a weak ref) and the implementation
30. // allows it to happen.
31.             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK  
32.                 && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);  
33.         }  
34. if
35.             decWeak(id);  
36. return false;  
37.         }  
38.         curCount = android_atomic_inc(&impl->mStrong);  
39.   
40. // If the strong reference count has already been incremented by
41. // someone else, the implementor of onIncStrongAttempted() is holding
42. // an unneeded reference.  So call onLastStrongRef() here to remove it.
43. // (No, this is not pretty.)  Note that we MUST NOT do this if we
44. // are in fact acquiring the first reference.
45. if
46.             impl->mBase->onLastStrongRef(id);  
47.         }  
48.     }  
49.   
50.     impl->addWeakRef(id);  
51.     impl->addStrongRef(id);  
52.   
53. #if PRINT_REFS
54. "attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);  
55. #endif
56.   
57. if
58.         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
59.         impl->mBase->onFirstRef();  
60.     }  
61.   
62. return true;  
63. }


        這個函數的作用是試圖增加目標對象的強引用計數,但是有可能會失敗,失敗的原因可能是因為目標對象已經被delete掉了,或者是其它的原因,下面會分 析到。前面我們在討論強指針的時候説到,增加目標對象的強引用計數的同時,也會增加目標對象的弱引用計數,因此,函數在開始的地方首先就是調用 incWeak函數來先增加目標對象的引用計數,如果後面試圖增加目標對象的強引用計數失敗時,會調用decWeak函數來回滾前面的incWeak操 作。

        這裏試圖增加目標對象的強引用計數時,分兩種情況討論,一種情況是此時目標對象正在被其它強指針引用,即它的強引用計數大於0,並且不等於 INITIAL_STRONG_VALUE,另一種情況是此時目標對象沒有被任何強指針引用,即它的強引用計數小於等於0,或者等於 INITIAL_STRONG_VALUE。

        第一種情況比較簡單,因為這時候説明目標對象一定存在,因此,是可以將這個弱指針提升為強指針的,在這種情況下,只要簡單地增加目標對象的強引用計數值就行了:



[cpp] view plain copy



1. while
2. if
3. break;  
4. }  
5. curCount = impl->mStrong;  
6.    }

        當我們在這裏對目標對象的強引用計數執行加1操作時,要保證原子性,因為其它地方也有可能正在對這個目標對象的強引用計數執行加1的操作,前面我們一般 是調用android_atomic_inc函數來完成,但是這裏是通過調用android_atomic_cmpxchg函數來完 成,android_atomic_cmpxchg函數是體系結構相關的函數,在提供了一些特殊的指令的體系結構上,調用 android_atomic_cmpxchg函數來執行加1操作的效率會比調用android_atomic_inc函數更高一些。函數 android_atomic_cmpxchg是在system/core/include/cutils/atomic.h文件中定義的一個宏:


[cpp] view plain copy


1. int
2. volatile
3.   
4. #define android_atomic_cmpxchg android_atomic_release_cas

        它實際執行的函數是android_atomic_release_cas,這個函數的工作原理大概是這樣的:如果它發現*addr == oldvalue,就會執行*addr = newvalue的操作,然後返回0,否則什麼也不做,返回1。在我們討論的這個場景中,oldvalue等於curCount,而newvalue等於 curCount + 1,於是,在*addr == oldvalue的條件下,就相當於是對目標對象的強引用計數值增加了1。什麼情況下*addr != oldvalue呢?在調用android_atomic_release_cas函數之前,oldvalue和值就是從地址addr讀出來的,如果在執 行android_atomic_release_cas函數的時候,有其它地方也對地址addr進行操作,那麼就會有可能出現*addr != oldvalue的情況,這時候就説明其它地方也在操作目標對象的強引用計數了,因此,這裏就不能執行增加目標對象的強引用計數的操作了,它必須要等到其 它地方操作完目標對象的強引用計數之後再重新執行,這就是為什麼要通過一個while循環來執行了。


        第二種情況比較複雜一點,因為這時候目標對象可能還存在,也可能不存了,這要根據實際情況來判斷。如果此時目標對象的強引用計數值等於 INITIAL_STRONG_VALUE,説明此目標對象還從未被強指針引用過,這時候弱指針能夠被提升為強指針的條件就為:



[cpp] view plain copy



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



            即如果目標對象的生命週期只受到強引用計數控制或者在目標對象的具體實現中總是允許這種情況發生。怎麼理解呢?如果目標對象的生命週期只受強引用計數控 制(它的標誌位mFlags為0),而這時目標對象又還未被強指針引用過,它自然就不會被delete掉,因此,這時候可以判斷出目標對象是存在的;如果 目標對象的生命週期受弱引用計數控制(OBJECT_LIFETIME_WEAK),這時候由於目標對象正在被弱指針引用,因此,弱引用計數一定不為0, 目標對象一定存在;如果目標對象的生命週期不受引用計數控制(BJECT_LIFETIME_FOREVER),這時候目標對象也是下在被弱指針引用,因 此,目標對象的所有者必須保證這個目標對象還沒有被delete掉,否則就會出問題了。在後面兩種場景下,因為目標對象的生命週期都是不受強引用計數控制 的,而現在又要把弱指針提升為強指針,就需要進一步調用目標對象的onIncStrongAttempted來看看是否允許這種情況發生,這又該怎麼理解 呢?可以這樣理解,目標對象的設計者可能本身就不希望這個對象被強指針引用,只能通過弱指針來引用它,因此,這裏它就可以重載其父類的 onIncStrongAttempted函數,然後返回false,這樣就可以阻止弱指針都被提升為強指針。在RefBase類中,其成員函數 onIncStrongAttempted默認是返回true的:



    [cpp] view plain copy


    1. bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)  
    2. {  
    3. return (flags&FIRST_INC_STRONG) ? true : false;  
    4. }


            如果此時目標對象的強引用計數值小於等於0,那就説明該對象之前一定被強指針引用過,這時候就必須保證目標對象是被弱引用計數控制的 (BJECT_LIFETIME_WEAK),否則的話,目標對象就已經被delete了。同樣,這裏也要調用一下目標對象的 onIncStrongAttempted成員函數,來詢問一下目標對象在強引用計數值小於等於0的時候,是否允計將弱指針提升為強指針。下面這個代碼段 就是執行上面所説的邏輯:



    [cpp] view plain copy


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

           繼續往下看:


    [cpp] view plain copy


    1. if
    2.     decWeak(id);  
    3. return false;  
    4. }  
    5. curCount = android_atomic_inc(&impl->mStrong);

            如果allow值為false,那麼就説明不允計把這個弱指針提升為強指針,因此就返回false了,在返回之前,要先調用decWeak函數來減少目 標對象的弱引用計數,因為函數的開頭不管三七二十一,首先就調用了incWeak來增加目標對象的弱引用計數值。


            函數attemptIncStrong的主體邏輯大概就是這樣了,比較複雜,讀者要細細體會一下。函數的最後,如果此弱指針是允計提升為強指針的,並且此目標對象是第一次被強指針引用,還需要調整一下目標對象的強引用計數值:



    [cpp] view plain copy


    1. if
    2.     android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);  
    3.     impl->mBase->onFirstRef();  
    4. }

            這個邏輯我們在前面分析強指針時已經分析過了,這裏不再詳述。


            分析到這裏,弱指針就介紹完了。強指針和弱指針的關係比較密切,同時它們也比較複雜,下面我們再舉一個例子來説明強指針和弱指針的用法,同時也驗證一下它們的實現原理。

            5. 強指針和弱指針的用法

            參考在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序一文,我們在external目錄下建立一個C++工程目錄weightpointer,它裏面有兩個文件,一個weightpointer.cpp文件,另外一個是Android.mk文件。

            源文件weightpointer.cpp的內容如下:



    [cpp] view plain copy


    1. #include <stdio.h>
    2. #include <utils/RefBase.h>
    3.   
    4. #define INITIAL_STRONG_VALUE (1<<28)
    5.   
    6. using namespace
    7.   
    8. class WeightClass : public
    9. {  
    10. public:  
    11. void
    12.         {  
    13.                 int32_t strong = getStrongCount();  
    14.                 weakref_type* ref = getWeakRefs();  
    15.   
    16. "-----------------------\n");  
    17. "Strong Ref Count: %d.\n", (strong  == INITIAL_STRONG_VALUE ? 0 : strong));  
    18. "Weak Ref Count: %d.\n", ref->getWeakCount());  
    19. "-----------------------\n");  
    20.         }  
    21. };  
    22.   
    23. class StrongClass : public
    24. {  
    25. public:  
    26.         StrongClass()  
    27.         {  
    28. "Construct StrongClass Object.\n");  
    29.         }  
    30.   
    31. virtual
    32.         {  
    33. "Destory StrongClass Object.\n");  
    34.         }  
    35. };  
    36.   
    37.   
    38. class WeakClass : public
    39. {  
    40. public:  
    41.         WeakClass()  
    42.         {  
    43.                 extendObjectLifetime(OBJECT_LIFETIME_WEAK);  
    44.   
    45. "Construct WeakClass Object.\n");  
    46.         }  
    47.   
    48. virtual
    49.         {  
    50. "Destory WeakClass Object.\n");  
    51.         }  
    52. };  
    53.   
    54. class ForeverClass : public
    55. {  
    56. public:  
    57.         ForeverClass()  
    58.         {  
    59.                 extendObjectLifetime(OBJECT_LIFETIME_FOREVER);  
    60.   
    61. "Construct ForeverClass Object.\n");  
    62.         }  
    63.   
    64. virtual
    65.         {  
    66. "Destory ForeverClass Object.\n");  
    67.         }  
    68. };  
    69.   
    70.   
    71. void
    72. {  
    73.         wp<StrongClass> wpOut = pStrongClass;  
    74.         pStrongClass->printRefCount();  
    75.   
    76.         {  
    77.                 sp<StrongClass> spInner = pStrongClass;  
    78.                 pStrongClass->printRefCount();  
    79.         }  
    80.   
    81.         sp<StrongClass> spOut = wpOut.promote();  
    82. "spOut: %p.\n", spOut.get());  
    83. }  
    84.   
    85. void
    86. {  
    87.         wp<WeakClass> wpOut = pWeakClass;  
    88.         pWeakClass->printRefCount();  
    89.   
    90.         {  
    91.                 sp<WeakClass> spInner = pWeakClass;  
    92.                 pWeakClass->printRefCount();  
    93.         }  
    94.   
    95.         pWeakClass->printRefCount();  
    96.         sp<WeakClass> spOut = wpOut.promote();  
    97. "spOut: %p.\n", spOut.get());  
    98. }  
    99.   
    100.   
    101. void
    102. {  
    103.         wp<ForeverClass> wpOut = pForeverClass;  
    104.         pForeverClass->printRefCount();  
    105.   
    106.         {  
    107.                 sp<ForeverClass> spInner = pForeverClass;  
    108.                 pForeverClass->printRefCount();  
    109.         }  
    110. }  
    111.   
    112. int main(int argc, char** argv)  
    113. {  
    114. "Test Strong Class: \n");  
    115. new
    116.         TestStrongClass(pStrongClass);  
    117.   
    118. "\nTest Weak Class: \n");  
    119. new
    120.         TestWeakClass(pWeakClass);  
    121.   
    122. "\nTest Froever Class: \n");  
    123. new
    124.         TestForeverClass(pForeverClass);  
    125.         pForeverClass->printRefCount();  
    126. delete
    127.   
    128. return
    129. }

            首先定義了一個基類WeightClass,繼承於RefBase類,它只有一個成員函數printRefCount,作用是用來輸出引用計數。接着分 別定義了三個類StrongClass、WeakClass和ForeverClass,其中實例化StrongClass類的得到的對象的標誌位為默認 值0,實例化WeakClass類的得到的對象的標誌位為OBJECT_LIFETIME_WEAK,實例化ForeverClass類的得到的對象的標 志位為OBJECT_LIFETIME_FOREVER,後兩者都是通過調用RefBase類的extendObjectLifetime成員函數來設置 的。


            在main函數裏面,分別實例化了這三個類的對象出來,然後分別傳給TestStrongClass函數、TestWeakClass函數和 TestForeverClass函數來説明智能指針的用法,我們主要是通過考察它們的強引用計數和弱引用計數來驗證智能指針的實現原理。

            編譯腳本文件Android.mk的內容如下:



    [plain] view plain copy


    1. LOCAL_PATH := $(call my-dir)  
    2. include $(CLEAR_VARS)  
    3. LOCAL_MODULE_TAGS := optional  
    4. LOCAL_MODULE := weightpointer  
    5. LOCAL_SRC_FILES := weightpointer.cpp  
    6. LOCAL_SHARED_LIBRARIES := \  
    7.         libcutils \  
    8.         libutils  
    9. include $(BUILD_EXECUTABLE)

            最後,我們參照

    如何單獨編譯Android源代碼中的模塊一文,使用mmm命令對工程進行編譯:


    [plain] view plain copy



    1. USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer  

            編譯之後,就可以打包了:


    [plain] view plain copy



    1. USER-NAME@MACHINE-NAME:~/Android$ make snod

            最後得到可執行程序weightpointer就位於設備上的/system/bin/目錄下。啓動模擬器,通過adb shell命令進入到模擬器終端,進入到/system/bin/目錄,執行weightpointer可執行程序,驗證程序是否按照我們設計的邏輯運 行:


    [plain] view plain copy


    1. USER-NAME@MACHINE-NAME:~/Android$ adb shell  
    2. root@android:/ # cd system/bin/          
    3. root@android:/system/bin # ./weightpointer

            執行TestStrongClass函數的輸出為:


    [plain] view plain copy


    1. Test Strong Class:   
    2. Construct StrongClass Object.  
    3. -----------------------  
    4. Strong Ref Count: 0.  
    5. Weak Ref Count: 1.  
    6. -----------------------  
    7. -----------------------  
    8. Strong Ref Count: 1.  
    9. Weak Ref Count: 2.  
    10. -----------------------  
    11. Destory StrongClass Object.  
    12. spOut: 0x0.



            在TestStrongClass函數裏面,首先定義一個弱批針wpOut指向從main函數傳進來的StrongClass對象,這時候我們可以看到 StrongClass對象的強引用計數和弱引用計數值分別為0和1;接着在一個大括號裏面定義一個強指針spInner指向這個StrongClass 對象,這時候我們可以看到StrongClass對象的強引用計數和弱引用計數值分別為1和2;當程序跳出了大括號之後,強指針spInner就被析構 了,從上面的分析我們知道,強指針spInner析構時,會減少目標對象的強引用計數值,因為前面得到的強引用計數值為1,這裏減1後,就變為0了,又由 於這個StrongClass對象的生命週期只受強引用計數控制,因此,這個StrongClass對象就被delete了,這一點可以從後面的輸出 (“Destory StrongClass Object.”)以及試圖把弱指針wpOut提升為強指針時得到的對象指針為0x0得到驗證。

            執行TestWeakClass函數的輸出為:



    [plain] view plain copy



    1. Test Weak Class:   
    2. Construct WeakClass Object.  
    3. -----------------------  
    4. Strong Ref Count: 0.  
    5. Weak Ref Count: 1.  
    6. -----------------------  
    7. -----------------------  
    8. Strong Ref Count: 1.  
    9. Weak Ref Count: 2.  
    10. -----------------------  
    11. -----------------------  
    12. Strong Ref Count: 0.  
    13. Weak Ref Count: 1.  
    14. -----------------------  
    15. spOut: 0xa528.  
    16. Destory WeakClass Object.



            TestWeakClass函數和TestStrongClass函數的執行過程基本一樣,所不同的是當程序跳出大括號之後,雖然這個 WeakClass對象的強引用計數值已經為0,但是由於它的生命週期同時受強引用計數和弱引用計數控制,而這時它的弱引用計數值大於0,因此,這個 WeakClass對象不會被delete掉,這一點可以從後面試圖把弱批針wpOut提升為強指針時得到的對象指針不為0得到驗證。

            執行TestForeverClass函數的輸出來:



    [plain] view plain copy



    1. Test Froever Class:   
    2. Construct ForeverClass Object.  
    3. -----------------------  
    4. Strong Ref Count: 0.  
    5. Weak Ref Count: 1.  
    6. -----------------------  
    7. -----------------------  
    8. Strong Ref Count: 1.  
    9. Weak Ref Count: 2.  
    10. -----------------------

           當執行完TestForeverClass函數返回到main函數的輸出來:


    [plain] view plain copy


    1. -----------------------  
    2. Strong Ref Count: 0.  
    3. Weak Ref Count: 0.  
    4. -----------------------  
    5. Destory ForeverClass Object.

     

            這裏我們可以看出,雖然這個ForeverClass對象的強引用計數和弱引用計數值均為0了,但是它不自動被delete掉,雖然由我們手動地 delete這個對象,它才會被析構,這是因為這個ForeverClass對象的生命週期是既不受強引用計數值控制,也不會弱引用計數值控制。


            這樣,從TestStrongClass、TestWeakClass和TestForeverClass這三個函數的輸出就可以驗證了我們上面對Android系統的強指針和弱指針的實現原理的分析。

            至此,Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理就分析完成了,它實現得很小巧但是很精緻,希望讀者可以通過實際操作細細體會一下。