Android上C++對象的自動回收機制分析

本文摘要

C++ 沒有像Java那樣的內建的對象自動回收機制,new創建的對象沒有delete,會一直存在於內存中。對象已經不再使用,但是如果忘記delete,會 造成內存資源的泄露。

1.       背景

C++ 沒有像Java那樣的內建的對象自動回收機制,new創建的對象沒有delete,會一直存在於內存中。對象已經不再使用,但是如果忘記delete,會 造成內存資源的泄露。在實際開發過程中,分析內存泄露是一件很棘手的事情。本文基於Android2.2系統源碼,對Android的C++對象自動回收 機制進行分析。

2.       引用計數和智能指針

Android上C++對象實現自動釋放的機制是使用引用計數+智能指針。對象的生命週期通過引用計數來管理,當引用計數>0時,對象不會被釋放;當引用計數=0時,釋放該對象。

使用對象的方式是通過智能指針引用該對象,智能指針也是C++對象,利用C++的構造析構自動調用的特性,在構造函數中將對象的引用計數加1,析構函數中減1,當計數減爲0時delete該對象,這樣通過智能指針+引用計數就實現了對象的自動化管理。

下面通過代碼分析具體實現過程。

3.       RefBase

Android 中C++類一般都會直接或間接繼承RefBase類,RefBase類有一個成員變量mRefs,mRefs是weakref_impl類 型,weakref_impl記錄着引用計數、目標對象(通過引用計數管理的對象)指針和符號位。通過繼承RefBase,使類具有引用計數的功能。

weakref_impl* const mRefs;

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;  // 標誌位,初始是OBJECT_LIFETIME_STRONG



};

在RefBase的構造函數中,mRefs指向了創建的weakref_impl對象。因此,繼承了RefBase的對象都會包含一個weakref_impl對象。

RefBase::RefBase()

    : mRefs(new weakref_impl(this))

{};
4.       強引用計數和弱引用計數

在討論智能指針前我們先考慮這樣一種情況。假設A對象是由MA模塊來創建和銷 毀的,MB模塊的B對象增加A對象的引用計數來使用A對象,有一種情況是:MA模塊比MB模塊提前被銷燬,由於B對象使用着A,A的引用計數不爲0,則A 不會被銷燬。在MA銷燬後B繼續使用A,假設A使用了MA模塊的其他對象或者資源,這時就會出問題,因爲MA模塊的其他對象或者資源已經銷燬了。

爲了解決上述問題,引用計數細分爲強引用計數和弱引用計數。一般情況下,強引用計數控制着對象生命週期,如果強引用計數減爲0時目標對象自動析構,即使弱引用計數不爲0。弱引用計數後面介紹。

5.       sp和wp

前 面說過,智能指針管理着對象的引用計數,Android中智能指針的實現是sp和wp。sp是strong pointer,wp是weak pointer。sp增加引用計數會分別將強引用計數和弱引用計數+1,wp增加引用計數時只會講弱引用計數+1,。因此,弱引用計數總是 >= 強引用計數。sp可以保證目標對象一直是有效的,但wp不能保證,因此wp不能直接調用目標對象的方法,wp需要提升爲sp後才能調用目標對象的方法。所 以wp沒有提供指針操作符重載方法(operator* ()和operator->)。


sp和wp分別定義在

frameworks/base/include/utils/StrongPointer.h和frameworks/base/include/utils/RefBase.h文件。


sp對象構造調用incStrong

template<typename T>

sp<T>::sp(T* other)

: m_ptr(other)

  {

    if (other) other->incStrong(this);

  }

incStrong將mStrong和mWeak分別加1,mStrong的值從INITIAL_STRONG_VALUE改爲1

void RefBase::incStrong(const void* id) const

{

    weakref_impl* const refs = mRefs;

    refs->incWeak(id); // mWeak += 1

   

    const int32_t c = android_atomic_inc(&refs->mStrong); // mStrong += 1

    …

    if (c != INITIAL_STRONG_VALUE)  {

        return;

    }

    …

    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);

}

sp對象析構調用decStrong

template<typename T>

sp<T>::~sp()

{

    if (m_ptr) m_ptr->decStrong(this);

}

decStrong分別將mStrong和mWeak 減1,mStrong減爲0時。如果mFlags的OBJECT_LIFETIME_STRONG被設置,調用delete this;析構目標對象。OBJECT_LIFETIME_STRONG是默認的情況,後面討論。

void RefBase::decStrong(const void* id) const

{

    …

    const int32_t c = android_atomic_dec(&refs->mStrong); // mStrong += 1

    …

if (c == 1) {



        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {

            delete this;

        }

    }

    refs->decWeak(id); // mWeak -= 1

}

wp對象的構造和析構過程也是類似的,構造時mWeak加1,析構時mWeak減1

6.       wp提升爲sp的過程

wp對象調用promote方法返回sp對象,如果sp指向的對象已經銷燬,promote返回NULL

template<typename T>

sp<T> wp<T>::promote() const

{

    sp<T> result;

    if (m_ptr && m_refs->attemptIncStrong(&result)) {

        result.set_pointer(m_ptr);

    }

    return result;

}

可以將wp提升爲sp的三種情況:

1、  沒有sp指向目標對象且mStrong == INITIAL_STRONG_VALUE

2、  沒有sp指向目標對象且mStrong == 0 且mFlags == OBJECT_LIFETIME_WEAK

3、有sp指向目標對象

attemptIncStrong()代碼說明了上面的三種情況

bool RefBase::weakref_type::attemptIncStrong(const void* id)

{

    incWeak(id);

   

    weakref_impl* const impl = static_cast<weakref_impl*>(this);

   

    int32_t curCount = impl->mStrong;

    LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",

               this);

    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;

        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) {

            decWeak(id);

            return false;

        }

        curCount = android_atomic_inc(&impl->mStrong);



        …

        }

    }

   

    impl->addStrongRef(id);

    …

    return true;

}
7.       weakref_impl對象標誌位的作用

當mFlags 爲OBJECT_LIFETIME_STRONG 時,強引用計數爲0時,銷燬對象

當 mFlags爲OBJECT_LIFETIME_WEAK時,強引用計數爲0時,不銷燬對象,弱引用減爲0時,才銷燬對象,由於弱引用計數 >= 強引用計數,所以OBJECT_LIFETIME_WEAK延長了對象的存在時間,下面的代碼說明了這種情況。當mWeak == 0 且 mFlags == OBJECT_LIFETIME_WEAK時,釋放目標對象。

void RefBase::weakref_type::decWeak(const void* id)

{

const int32_t c = android_atomic_dec(&impl->mWeak);

if (c != 1) return;



         if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {

        …

    } else {

        // less common case: lifetime is OBJECT_LIFETIME_

        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;

        }

    }

}
8.       其他特性

RefBase提供了以下四個重載方法,子類可以繼承實現,以便跟蹤引用計數的變化情況。

// 當mStrong從INITIAL_STRONG_VALUE更改爲1時,該方法被調用

virtual void            onFirstRef();

// 當mStrong從減爲0時,該方法被調用

virtual void            onLastStrongRef(const void* id);

// 控制是否允許將wp提升爲sp,返回true表示允許

virtual bool            onIncStrongAttempted(uint32_t flags, const void* id)

// 當mWeak減爲0時且mFlags == OBJECT_LIFETIME_WEAK,該方法被調用

virtual void            onLastWeakRef(const void* id);
9.       總結

RefBase爲C++對象提供了引用計數,sp和wp通過管理引用計數,達到自動控制目標對象生存期的目的。

發佈了13 篇原創文章 · 獲贊 16 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章