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