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

 by http://www.cnblogs.com/tonyhan/archive/2011/12/26/2302585.html


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

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_{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;

}

}

}
複製代碼

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通過管理引用計數,達到自動控制目標對象生存期的目的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章