Android智能指針輕量級Light Pointer初識
引言
相信有很多小伙伴跟我一樣,一直從事Android上層應(yīng)用開發(fā),對Android底層充滿興趣,奈何基礎(chǔ)知識薄弱,每次學(xué)習(xí)源碼進(jìn)入native層的時候,都想放棄。不用灰心,一遍看不懂就再來一遍,今天主要是分享Android智能指針的內(nèi)容。
作為上層應(yīng)用開發(fā)者對C++不是很熟悉,不要慌,咱們一步一步來,接下來我將分為3篇文章來講解智能指針
1、智能指針初探——輕量級指針(Light Pointer)
2、智能指針初探——強(qiáng)指針(Strong Pointer)(未更新)
3、智能指針初探——弱指針(Weak Pointer)(未更新)
本篇是智能指針初探——輕量級指針(Light Pointer),在講解智能指針之前我們先思考下為什么java沒有指針。
java
做Android上層應(yīng)用開發(fā)肯定離不開java,很多人選擇學(xué)習(xí)java最主要的原因是沒有指針,再也不用擔(dān)心各種指針和內(nèi)存釋放了。
//java Object a = new Object();
java在設(shè)計中盡量淡化了指針的概念,我們可以簡單的new對象,上面示例代碼就是java生成一個對象的最簡單樣例,我們可以通過變量a去使用剛剛new好的Object對象。變量a是一個對象類型或者說是引用類型,作用其實(shí)跟C/C++中的指針類似。
java中引用分為如下4類,感興趣的同學(xué)可以自行去學(xué)習(xí):
引用類型 | 概述 |
---|---|
StrongReference(強(qiáng)引用) | 強(qiáng)引用是最經(jīng)常使用的一種引用,如new操作創(chuàng)建的對象就屬于強(qiáng)引用,只要強(qiáng)引用關(guān)系還存在,垃圾收集器就不會回收掉被引用的對象。 |
SoftReferenc(軟引用) | 內(nèi)存空間足夠,垃圾回收器就不會回收它,如果內(nèi)存空間不足了,就會回收這些對象的內(nèi)存,只要垃圾回收器沒有回收它,該對象就可以被程序使用。 |
WeakReferenc(弱引用) | 弱引用也是用來描述那些非必須對象,但是它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾收集發(fā)生為止。當(dāng)垃圾收集器開始工作,無論當(dāng)前內(nèi)存是否足夠,都會回收掉只 被弱引用關(guān)聯(lián)的對象 |
PhantomReference(虛引用) | 虛引用也稱為“幽靈引用”或者“幻影引用”,它是最弱的一種引用關(guān)系。一個對象是否有虛引用的 存在,完全不會對其生存時間構(gòu)成影響,也無法通過虛引用來取得一個對象實(shí)例。為一個對象設(shè)置虛 引用關(guān)聯(lián)的唯一目的只是為了能在這個對象被收集器回收時收到一個系統(tǒng)通知。 |
這些引用類型配合Java垃圾回收機(jī)制(GC),讓我們java程序員不用太關(guān)心內(nèi)存的釋放。Java垃圾回收機(jī)制正是由java虛擬機(jī)(JVM)提供,在Android也有對應(yīng)的虛擬機(jī):Dalvik 虛擬機(jī)(Dalvik Virtual Machine),ART(Android Runtime)虛擬機(jī)。 java在進(jìn)行垃圾回收機(jī)制(GC)時,需要做兩件事:
1、判斷該對象是否為垃圾
2、垃圾回收的具體算法
判斷該對象是否為垃圾
1、引用計數(shù)法
原理其實(shí)很簡單,給運(yùn)行的對象添加一個引用計數(shù)器,每當(dāng)有一個地方引用它時,計數(shù)器+1;當(dāng)引用失效時,計數(shù)器就-1,任何時刻計數(shù)器為0的對象,就視作不可能再被使用。這一種方式,實(shí)現(xiàn)簡單,邏輯也清晰,大部分的情況下,它都可以達(dá)到很好的效果,盡管這樣,計數(shù)器算法還是存在但是的,但是它無法解決循環(huán)引用的場景(A、B兩個對象相互引用)。
2、可達(dá)性分析法
通過一系列稱為“GC Roots”的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索走過的路徑稱為“引用鏈”,當(dāng)一個對象到 GC Roots 沒有任何的引用鏈相連時(從 GC Roots 到這個對象不可達(dá))時,證明此對象不可用。
GC Roots包含以下:
- 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象
- 方法區(qū)中類靜態(tài)屬性引用的對象
- 方法區(qū)中常量引用的對象
- 本地方法棧中JNI(即一般說的native方法)中引用的對象
......
雖然這些虛擬機(jī)已幫忙我們回收內(nèi)存,但其實(shí)我們做上層應(yīng)用開發(fā)時還是得特別需要注意引用,不然還是會造成OOM等異常。
垃圾回收的具體算法
java垃圾回收的算法有很多這里就不詳細(xì)展開了(標(biāo)記-清除算法、 標(biāo)記-整理算法、 復(fù)制算法、分代收集算法...),感興趣的同學(xué)可以自行學(xué)習(xí)
C++
相比較java的引用+垃圾回收機(jī)制,C++沒有垃圾回收的機(jī)制,通常使用引用計數(shù)的方法來統(tǒng)計對象的使用情況,為了實(shí)現(xiàn)引用計數(shù),需要有個類來負(fù)責(zé)計數(shù),我們先看下最簡單的輕量級指針(Light Pointer)。
本文中的源代碼可下面鏈接查看:
輕量級指針(Light Pointer)
我們希望指針指向的對象有引用計數(shù)功能,當(dāng)計數(shù)為0時,刪除對象,所以需要有個類能夠?qū)崿F(xiàn)引用計數(shù)的功能。
輕量級指針(Light Pointer)的引用計數(shù)類就是它:LightRefBase(system/core/include/utils/RefBase.h)
template <class T> class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(const void* id) const { android_atomic_inc(&mCount); } inline void decStrong(const void* id) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast<const T*>(this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount; } protected: inline ~LightRefBase() { } private: mutable volatile int32_t mCount; };
我們簡單看下這個類,重點(diǎn)關(guān)注mCount這個變量的使用,在incStrong中+1,在decStrong是-1(當(dāng)前mCount為1時,再減就要為0了,就會delete對象)。
好了,現(xiàn)在我們有了引用計數(shù)類之后,還缺少一個關(guān)鍵角色:指針sp(system/core/include/utils/StrongPointer.h)
template<typename T> class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp<T>& other); sp(sp<T>&& other); template<typename U> sp(U* other); template<typename U> sp(const sp<U>& other); template<typename U> sp(sp<U>&& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp<T>& other); sp& operator = (sp<T>&& other); template<typename U> sp& operator = (const sp<U>& other); template<typename U> sp& operator = (sp<U>&& other); template<typename U> sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template<typename Y> friend class sp; template<typename Y> friend class wp; void set_pointer(T* ptr); T* m_ptr; };
sp類是個模版類,主要的工作就是指針指向m_ptr,在構(gòu)造函數(shù)、析構(gòu)函數(shù)、重載函數(shù)(operator =)中控制m_ptr中的計數(shù),而m_ptr指向的對象就是繼承自LightRefBase。
//以下只截取了部分代碼,詳細(xì)代碼內(nèi)容參考 StrongPointer.h //普通構(gòu)造函數(shù) template<typename T> sp<T>::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } //拷貝構(gòu)造函數(shù) template<typename T> sp<T>::sp(const sp<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); } //析構(gòu)函數(shù) template<typename T> sp<T>::~sp() { if (m_ptr) m_ptr->decStrong(this); } //重載函數(shù)(operator =) template<typename T> sp<T>& sp<T>::operator =(const sp<T>& other) { T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; return *this; }
那么我們該如何使用輕量級指針(Light Pointer):
只需繼承自LightRefBase結(jié)合sp即可。
class MyLightRefClass : public LightRefBase<MyLightRefClass> { public: MyLightRefClass() { } virtual ~MyLightRefClass() { } }; int main(int argc, char** argv) { MyLightRefClass* lightClass = new MyLightRefClass(); sp<MyLightRefClass> lp = lightClass; }
輕量級指針的分享就結(jié)束了,輕量級指針很簡單但是有一個問題沒有解決:A、B相互引用,關(guān)于后面的強(qiáng)指針、弱指針還請繼續(xù)關(guān)注
以上就是Android智能指針輕量級Light Pointer初識的詳細(xì)內(nèi)容,更多關(guān)于Android輕量級指針Light Pointer的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Android .9.png “點(diǎn)九”圖片的使用
這篇文章主要為大家詳細(xì)介紹了Android .9.png “點(diǎn)九”圖片的使用方法,感興趣的小伙伴們可以參考一下2016-09-09Android7.0版本影響開發(fā)的改進(jìn)分析
這篇文章主要介紹了Android7.0版本影響開發(fā)的改進(jìn),總結(jié)分析了Android7.0版本中比較常見的開發(fā)注意事項與操作技巧,需要的朋友可以參考下2017-11-11Android List刪除重復(fù)數(shù)據(jù)
這篇文章主要介紹了Android List刪除重復(fù)數(shù)據(jù)的實(shí)例代碼,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-06-06Android開發(fā)實(shí)現(xiàn)ListView部分布局監(jiān)聽的方法
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)ListView部分布局監(jiān)聽的方法,結(jié)合實(shí)例形式分析了Android通過設(shè)置tag標(biāo)志位實(shí)現(xiàn)ListView部分布局監(jiān)聽的相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Android應(yīng)用閃屏頁延遲跳轉(zhuǎn)的三種寫法
這篇文章主要介紹了 Android應(yīng)用閃屏頁延遲跳轉(zhuǎn)的三種寫法,需要的朋友可以參考下2017-03-03Android Broadcast 和 BroadcastReceiver的權(quán)限限制方式
這篇文章主要介紹了Android Broadcast 和 BroadcastReceiver的權(quán)限限制方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03使用ViewPager實(shí)現(xiàn)android軟件使用向?qū)Чδ軐?shí)現(xiàn)步驟
現(xiàn)在的大部分android軟件,都是使用說明,就是第一次使用該軟件時,會出現(xiàn)向?qū)?,可以左右滑動,然后就進(jìn)入應(yīng)用的主界面了,下面我們就實(shí)現(xiàn)這個功能2013-11-11基于Android中dp和px之間進(jìn)行轉(zhuǎn)換的實(shí)現(xiàn)代碼
本篇文章是對在Android中dp和px之間進(jìn)行轉(zhuǎn)換的實(shí)現(xiàn)方法進(jìn)行了分析介紹,需要的朋友參考下2013-05-05android SectorMenuView底部導(dǎo)航扇形菜單的實(shí)現(xiàn)代碼
這篇文章主要介紹了android SectorMenuView底部導(dǎo)航扇形菜單的實(shí)現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02