Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的智能指針

Android中的智能指針

編輯:關於Android編程

 

 

1 智能指針的設計思想 Java和C++語言很重要的一個區別就是Java中沒有指針這個概念,這裡只是沒有這個概念,內部使用時還是用到指針,只是將其隱藏起來,包裝起來,讓開發者不必擔心指針的問題。先來看一個下C++中常見的關於指針的問題 1 指針沒有初始化:變量在使用前要記得初始化,這個問題很好解決,將指針默認設置為null。 2 new 對象之後沒有及時delete:該對象占用的內存空間沒有及時的回收,使得系統可用的內存空間越來越少,很有可能最終導致內存溢出,出現崩潰 3 野指針:ptr=new Object ,創建了一個對象Object,且指針ptr指向它,當Object使用結束之後也delete了,但是沒有做的操作就是沒有將ptr清空,這樣ptr仍然指向了該Object對象的地址。結果在使用時ptr不為空,可以使用,但是此時Object對象已經delete了,Object所在的地址上的對象可能已經發生了變化,還用ptr訪問的話就可能出現未知錯誤。
如何解決這些問題呢? 對於第一個問題,很好解決,在初始化時設置為null即可 對於第二個問題,實現new和delete的同時操作,在new一個對象之後,要記得及時delete。 假如這裡封裝一個智能指針類SmartPointer,那麼SmartPoint類中要保存object的內存地址,且這個SmartPoint是一個模板類,設計如下:
template 
class SmartPointer
{
 //初始化時將m_ptr設置為空,這樣第一個問題就解決了
 inline SmartPointer(): m_ptr(0){}
 private:
     T* m_ptr;//保存object對象的地址
}
初始化時將m_ptr設置為空,第一個問題解決了,那麼如果如何判斷一個對象需要delete呢:當這個對象不再被需要時,換句話說就是沒有一個指針指向該對象時,就可以認為這個對象不再被需要了。常用的解決方案就是使用一個計數器來記錄該對象目前被指針指向的次數,每被指向一次,該對象的計數加一;每次SmartPointer析構時,該對象的計數器減一,如果計數器的值為0時,就可以刪除該對象了。 這裡使用封裝一個父類,該父類表示一個對象,這個對象內部維護一個int類型的指針,記錄當前該對象被指針指向的次數:
template 
class LightRefBase
{
public:
     inline LightRefBase():mCount(0){}
     inline void incStrong() const//引用計數加一
     {
          android_atomic_inc(&mCount);
     }
     inline void decStrong() const//引用計數減一
     {
          if(android_atomic_dec(&mCount)==1)
          {
               delete static_cast(this);//如果沒有被引用就直接刪除該對象
          }          

     }
private:
     mutable volatile int32_t mCount;//引用計數的個數
}
上面是對象類,有兩個關於引用計數的操作,incStrong和decStrong,這兩個函數又分別在SmartPointer的“=”賦值操作和析構操作時調用:
template 
class SmartPoint
{
     inline SmartPointer():m_ptr(0){}
     ~wp();
     SmartPointer& operator = (T* other);
private:
     T* m_ptr;
}
當為SmartPointer賦值時,要將該Object對象的引用計數加一,所以要重載賦值運算符:
SmartPointer &SmartPointer::operator=(T* other)
{
          if(other!=null)
          {
               m_ptr=other;//指向該對象other
               other->incStrong();//other引用計數加一
          }
          return *this;
}
析構時,要調用對象的decStrong,減少引用計數
wp::~wp()
{
     if(m_ptr) m_ptr-
假如現在又兩個SmartPointer指向一個對象,那麼效果如下:
\


有了這個引用計數,不用擔心對象沒有及時delete了,那麼第二個問題就解決了。同時第三個問題也解決了。






2 Android中智能指針的實現
Android中智能指針的實現有兩種,一個是Strong Pointer強指針(簡稱sp),一個是Weak Pointer弱指針(簡稱wp)。



2.1 sp
先看sp,它對應的文件在frameworks/native/include/utils/StrongPointer.h文件中
template 
class sp
{
public:
    inline sp() : m_ptr(0) { }

    sp(T* other);
    sp(const sp& other);
    template sp(U* other);
    template sp(const sp& other);

    ~sp();
// Assignment

    sp& operator = (T* other);
    sp& operator = (const sp& other);
private:    
    template friend class sp;
    template friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};
這裡還考慮了如果是為已賦值的SmartPointer重新賦值的情況,需要先撤銷之前指向的對象
template
sp& sp::operator = (T* other)
{
    if (other) other->incStrong(this);//other對象引用計數加一
    if (m_ptr) m_ptr->decStrong(this);//原來對象的引用計數減一
    m_ptr = other;//現在m_ptr指向other
    return *this;
}
可以看出sp的操作和之前SmartPointer的操作類似,都是直接對引用計數的加一或者減一,這種類型的指針還是很好理解的,下面看看wp指針
2.2 wp 再看wp弱引用 已經有了強引用,為什麼還要用弱引用呢?假如現在又兩個類:CDad,CChild
struct CDad
{
     CChild *myChild;
}

Struct CChild
{
     CDad *myDad;
}
而且他們之間很有可能出現這個情況:互相引用 \
這樣就處於死鎖狀態,兩者都處於被需要狀態,不能被釋放,這個時候就出現了弱引用,具體做法: CDad使用強指針引用CChild對象,而CChild只能使用弱引用指向CDad。規定當強引用計數為0時,不管弱引用是否為0都要delete自己,一旦delete自己就能打破僵局,避免死鎖的出現。那麼看看wp的實現,它的實現和sp還是有一些差別的,看它類之間的關系: \

template 
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;
    
    inline wp() : m_ptr(0) { }//構造函數

    wp(T* other);
   ~wp();
    
    // Assignment

    wp& operator = (T* other);
    sp promote() const;//將wp轉換為sp函數

private:
    T*              m_ptr; //指向目標對象
    weakref_type*   m_refs;//指向weakref_type類型的對象
};
要注意一下幾點: 1 除了指向目標對象的m_ptr還有一個指向weakref_type類型的對象,weakref_type是用來管理wp的類,由weakref_impl子類實現 2 一個的方法就是promote方法,可以將wp升級為sp,後面會涉及到 3 這裡的目標對象不再是sp中的LightRefBase,而是其父類RefBase,這個父類不僅僅需要處理sp的情況,還要處理wp的情況。
這裡舉一個例子,看下面代碼
class A:public RefBase//該類繼承RefBase
{
     //空實現
}
int main()
{
          A* pA = new A;//創建一個對象並讓pA指向它
          {
               sp spA(pA);//先創建一個sp,在創建一個wp
               wp wpA(spA);
          }
          //之後析構wp,再析構sp
}
一步一步的看,構造A對象,它繼承RefBase,所以使用的RefBase的構造函數 1 構造 RefBase對象
RefBase::RefBase()
    : mRefs(new weakref_impl(this))//創建一個weakref_impl類型對象,並賦值給mRefs
{
}
RefBase中維護了一個weakref_impl類型的mRefs,weakref_impl繼承weakref_type類,簡要看一下weakref_impl類和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)//強引用計數INITIAL_STRONG_VALUE 等於0x1000000
        , mWeak(0)//弱引用計數初始化為0
        , mBase(base)//保存傳入的base值,就是目標對象
        , mFlags(0)//保存生命周期標志,默認為Strong
        , mStrongRefs(NULL)
        , mWeakRefs(NULL)
        , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
        , mRetain(false)
    {
    }

     // 其他一些函數.....
}
可以看出weakref_impl的構造函數主要操作就是為mStrong和mWeak設置初始值,而RefBase的構造就是創建一個weakref_impl對象並賦值給mRefs成員變量。
2 創建sp
 sp spA(pA);
看sp的構造函數,在StrongPointer.h文件中
template
sp::sp(T* other)//other就是1中創建的pA對象
: m_ptr(other)//將other賦值給m_ptr對象
  {
    if (other) other->incStrong(this);
  }
調用pA的incStrong函數,也就是RefBase的incStrong函數:
void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;//mRefs就是RefBase構造時創建的weakref_impl對象
    refs->incWeak(id);    //讓impl的mWeak變量加一 
    refs->addStrongRef(id);///調試使用,非調試沒有具體操作 
     // c的值為自加之前的值,mStrong的值初始化為0x1000000,增加以後就是0x1000001
    const int32_t c = android_atomic_inc(&refs->mStrong);   
    if (c != INITIAL_STRONG_VALUE)  {
        return;//c的值如果不是INITIAL_STRONG_VALUE,直接返回
    }
     //否則,如果是INITIAL_STRONG_VALUE,也就是第一次使用,進行下面操作
     //將mStrong-INITIAL_STRONG_VALUE ,0x1000001-0x1000000=1 
    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    refs->mBase->onFirstRef();//第一次引用時調用onFirstRef 做一些初始化工作
}
其中調用了incWeak函數:
void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast(this);
    impl->addWeakRef(id);//調試使用,非調試沒有具體操作
    const int32_t c = android_atomic_inc(&impl->mWeak);//讓impl的mWeak變量加一,這個時候mWeak為0+1=1  
}
可以看出sp構造調用了RefBase的incStrong函數,對mRefs中的mWeak和mStrong進行操作,使得mWeak值為1,mStrong也為1
3 wp的構造函數 wp wpA(spA); 這裡出現了wp類,它的定義和sp有些不同,上面已經說明了,直接看wp的構造函數,在RefBase.h文件中
template
wp::wp(const sp& other)
    : m_ptr(other.m_ptr)//sp中的m_ptr指向目標對象,將sp的m_ptr的值賦值給wp的m_ptr
{
    if (m_ptr) {
        m_refs = m_ptr->createWeak(this);//調用pA的createWeak 方法,並保存返回知道m_refs
    }
}
這裡沒有增加引用計數,而是調用RefBase類的createWeak函數,該函數在RefBase.cpp文件中:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);//使得mRefs的mWeak 再次加一,此時mWeak 等於2
    return mRefs;//返回mRefs 
}
createWeak實現就是讓mRefs的mWeak加一,並返回mRefs,這樣wp中m_refs也指向mRefs變量,這是mStrong為1,mWeak為2
4 wp的析構函數 這個時候就意味著wp的生命快結束了,看它的析構函數,在RefBase.h文件中
template
wp::~wp()
{
    if (m_ptr) m_refs->decWeak(this);//調用m_refs的decWeak 函數
}
還記得createWeak,wp的m_refs指向mRefs變量,所以就是調用weakref_type的decWeak函數,在RefBase.cpp文件中
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast(this);
    impl->removeWeakRef(id);//調試使用,非調試不做任何操作
     //取出mWeak的值,此時為2保存到c中,並減一,此時為1
    const int32_t c = android_atomic_dec(&impl->mWeak);   
    if (c != 1) return;//由於c==2,返回
     // 如果c==1的話,這個時候減一之後,mWeak=0,說明弱引用沒有指向目標對象,額可以考慮釋放內存
     //OBJECT_LIFETIME_xxxxxx代表生命周期 
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlive the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;//釋放目標對象
        } else {
             delete impl;//釋放weakref_impl對象
        }
    } else {
        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
            // is gone, we can destroy the object.
            delete impl->mBase;
        }
    }
}
可以看出wp析構之後,mWeak減一變成1,mStrong沒有被操作,仍然是1,這個時候目標對象和weakref_impl對象都沒有真的被回收
5 sp析構函數 自己sp的析構函數,在StrongPointer.h文件中:
template
sp::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);//調用目標對象的desStrong函數
}
這裡的目標函數類型是RefBase類型,看RefBase的decStrong函數,在RefBase.cpp文件中:
void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;//賦值refs為RefBase的mRefs值
    refs->removeStrongRef(id);//調試使用,非調試不做任何操作 
     //取出mStrong的值,為1,賦值給c,並讓mStrong減一變成0
    const int32_t c = android_atomic_dec(&refs->mStrong); 
    if (c == 1) {//符合條件
        refs->mBase->onLastStrongRef(id);
        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;//刪除目標對象
        }
    }
    refs->decWeak(id);
}
這裡c==1,符合條件,調用delete this,也就是RefBase的析構函數:
RefBase::~RefBase()
{
    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {//mStrong  =0,不符合
        // we never acquired a strong (and/or weak) reference on this object.
        delete mRefs;
    } else {
        // life-time of this object is extended to WEAK or FOREVER, in
        // which case weakref_impl doesn't out-live the object and we
        // can free it now.
        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {//進入這裡
            // It's possible that the weak count is not 0 if the object
            // re-acquired a weak reference in its destructor
            if (mRefs->mWeak == 0) {//此時mWeak  的值為1,不是0,不符合條件
                delete mRefs;
            }
        }
    }
    // for debugging purposes, clear this.
    const_cast(mRefs) = NULL;
}
可以看出RefBase的析構函數並沒有符合條件,沒有刪除weakref_impl對象。在RefBase的析構函數執行之後再一次執行 refs->decWeak(id),在此之前mStrong=0,mWeak=1
void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast(this);
    impl->removeWeakRef(id);//調試使用,非調試不做任何操作
     //取出mWeak的值,此時為1保存到c中,並減一,此時為0
    const int32_t c = android_atomic_dec(&impl->mWeak);   
    if (c != 1) return;//由於c==1,不符合
     // 如果c==1的話,這個時候減一之後,mWeak=0,說明弱引用沒有指向目標對象,額可以考慮釋放內存
     //OBJECT_LIFETIME_xxxxxx代表生命周期 
    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
        if (impl->mStrong == INITIAL_STRONG_VALUE) {        
            delete impl->mBase;//釋放目標對象
        } else {//進入這個條件判斷
             delete impl;//釋放weakref_impl對象
        }
    } else {        
        impl->mBase->onLastWeakRef(id);
        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
            delete impl->mBase; //釋放目標對象 
        }
    }
}

到此為止一個整體的過程結束,總結一下 RefBase中有一個weakref_impl類型的mRefs,weakref_impl類型維護兩個重要的變量mWeak和mStrong。而RefBase的構造就是創建一個weakref_impl對象並賦值給mRefs成員變量,weakref_impl的構造函數主要操作就是為mStrong和mWeak設置初始值,其中mStrong為0x1000000,mWeak為0 sp構造時mStrong和mWeak都加一,sp析構時mStrong和mWeak都減一 wp構造時mWeak加一,wp析構時mWeak減一 RefBase徹底清除包括目標對象和weakref_impl類型的mRefs兩者的清除。如果flag=0時,也就是OBJECT_LIFETIME_STRONG時,如果mStrong=0,刪除實際目標對象;如果mWeak=0,刪除weakref_impl類型的mRefs
3 wp其他知識
3.1 wp變成sp 在wp還有一個重要的函數promote,它的作用就是得到一個sp,看下面 一個例子
int main()
{
     A  *pA = new A();
     wp wpA(pA);
     sp spA = wpA.promote();
}
其中wp構造之後mWeak變成1,mStrong還是初始值0x100000。再看promote函數,在RefBase.h文件中:
template
sp wp::promote() const
{
    sp result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {//關鍵函數是attempIncStrong函數
        result.set_pointer(m_ptr);//將m_ptr賦值給result的m_ptr
    }
    return result;
}
這裡調用了attemptIncStrong函數,它在RefBase.cpp文件中:
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);//mWeak加一,變成2
    
    weakref_impl* const impl = static_cast(this);
    //取出mStrong的值,這裡是0x1000000
    int32_t curCount = impl->mStrong;   
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
            break;
        }
        curCount = impl->mStrong;
    }
    
    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        bool allow;//判斷是否允許從wp生成sp
        if (curCount == INITIAL_STRONG_VALUE) {
            // Attempting to acquire first strong reference...  this is allowed
            // if the object does NOT have a longer lifetime (meaning the
            // implementation doesn't need to see this), or if the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        } else {
            // Attempting to revive the object...  this is allowed
            // if the object DOES have a longer lifetime (so we can safely
            // call the object with only a weak ref) and the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        }
        if (!allow) {
             如果不允許,則mWeak減一,並返回
            decWeak(id);
            return false;
        }
        // 如果允許則mStrong加一
        curCount = android_atomic_inc(&impl->mStrong);

        // If the strong reference count has already been incremented by
        // someone else, the implementor of onIncStrongAttempted() is holding
        // an unneeded reference.  So call onLastStrongRef() here to remove it.
        // (No, this is not pretty.)  Note that we MUST NOT do this if we
        // are in fact acquiring the first reference.
        if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
            impl->mBase->onLastStrongRef(id);
        }
    }
    
    impl->addStrongRef(id);//調試使用,沒有具體操作
    if (curCount == INITIAL_STRONG_VALUE) {
        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
        impl->mBase->onFirstRef();
    }
    //返回成功 
    return true;
}
promote執行之後mStrong和mWeak都加一,這時mWeak為2,mStrong為1,最終並返回一個sp對象,該對象指向wp指向的目的對象。
3.2 extendObjectLifetime RefBase中extendObjectLifetime函數的作用是延長對象的生命周期,不再受到強弱引用的影響。
void RefBase::extendObjectLifetime(int32_t mode)
{
    android_atomic_or(mode, &mRefs->mFlags);//or運算
}
其中定義了兩種生命周期,mFlag默認是0,也就是Strong,可以設置為weak,設置完之後,對於刪除目標對象時的判斷有所不同。
//! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

















 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved