編輯:關於Android編程
長久以來,C++中的內存管理問題一直讓人頭疼,空指針,野指針,內存洩露。。。。。。C++程序員看到這樣的問題就是各種頭大!這樣的問題往往很難解決,尤其是代碼架構比較龐大或者復雜的時候。但是同樣是面向對象的JAVA語言卻沒有這個問題,為什麼呢?因為java有GC,也就是垃圾回收而C++沒有。C++的做法是:程序員必須做到在new一個對象之後當不需要使用它的時候必須delete這個對象。看來很好,沒有問題是吧?但是,在實際的項目中,就是會有人忘記去delete這個對象,或者隨意delete一個對象,導致依賴這個對象的別的模塊發生野指針錯誤。這幾乎是經常發生的,而且是很難避免的。
Android中除了framework之上是Java語言寫就的,其余native層到kernel之上這部分基本都是C++寫成的。Android的這部分代碼量還是比較龐大的,那麼它是怎麼解決上面提到的C++內存問題的呢?為此,android引入了一個”智能指針“的概念,其實這個概念並不是android提出的,這個概念在C++的boost中就有的,google只是拿過來做了一個精簡版本罷了。
這裡我們專注了解android中的智能指針是怎麼實現的。Android的智能指針其實是比較復雜的,一時半會也說不清楚,在正式分析android的智能指針代碼之前,我們繼續上面的C++內存問題探討。
前面提到,在C++中需要new和delete配對使用,而且是程序員手動顯式執行。這對於程序員的要求是很高的,程序員需要知道什麼時候new了一個對象,什麼時候這個對象肯定是不需要的了然後采取delete它。這似乎有些理想,因為很多情況下不是這樣的,有的時候我們new一個對象然後這個對象就是給別的模塊使用的,別的模塊又是由別的小組或者公司維護的,他們很可能不會及時delete這個對象。那有什麼辦法可以解決這個問題呢?我們很容易會想到,專門造一個模塊,這個模塊來關於眾多產生的對象,然後同時負責這些對象的銷毀。但是,這個方案有一個問題,如果需要產生多個管理模塊的情況下,怎麼保證多個模塊之間的引用是一致的呢?也就是說可能管理模塊A持有某個對象的引用,然後某塊B也持有這個對象的引用,這樣的話這兩個模塊之間怎麼協調這個對象的引用問題呢?這是比較復雜的,也會有很多潛在的問題。那還有什麼辦法呢?要解決這個問題需要理解一個事情,那就是對象的引用計數問題,這是java的GC實現的基礎。所謂引用計數就是這個對象在幾個地方被使用了,比如:
Object a = new Object();
Object b = a;
這兩行代碼中,新new出來的對象有兩個引用計數,引用a和引用b同時指向同一塊內存空間。那什麼時候我們就不需要這個對象了呢?那就是他不需要的時候?這有點像廢話,但是事實就是這樣,只要當這個對象的引用計數等於0的時候,這個對象就不需要了。這樣以來,這個問題就轉化為:找到誰對這個對象的引用技術最為清楚?誰最直接了解這個對象的引用計數?對了!答案就是這個對象它自己!!!什麼?你要這個對象自己delete自己,聽起來有點荒謬,但是android中的智能指針就是這麼做的。
這是個android中給出的一個輕量級的智能指針解決方案,使用的思想就是我們上面分析的思想。為了讓對象可以做到自己delete自己,我們需要給所有的對象做一個公共的基類,這個LightRefBase就是這個基類。在分析這個代碼之前,我們先看一下,這個東西我們怎麼使用,以下是一個使用它的demo:
/*************************************************************************
> File Name: lightpointer.cpp
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Fri 22 Apr 2016 03:27:28 PM CST
************************************************************************/
#include
// 包含需要的頭文件
#include
using namespace android;
// 目標類必須是LightRefBase的子類
class LightClass : public LightRefBase
{
public:
LightClass()
{
printf("create instance of lightclass. \n");
}
virtual ~LightClass()
{
printf("destory instance of lightclass. \n");
}
};
int main(int argc, char** argv)
{
// new一個對象,並且將指針指向它
LightClass* ptr = new LightClass();
// 打印引用計數,就是看看有多少個地方使用了它,當然這裡還沒有顯式引用,結果應該是0.
printf("1. Light ref count: %d. \n", ptr->getStrongCount());
// sp<>這樣的引用就是顯式引用,是的一個指針指向它,然後我們看下現在的引用計數是多少
// 按照推理,應該是1.
sp ptrOut = ptr;
printf("2. Light ref count: %d. \n", ptr->getStrongCount());
// 代碼塊,在代碼塊內部再弄一個指針指向這個對象,然後再看一下引用計數
{
sp ptrInner = ptr;
printf("3. Light ref count: %d. \n", ptr->getStrongCount());
}
// 再代碼塊的外面,我們看一下引用計數。由於在代碼塊的外面,代碼塊的內部的那個
// 指向指針應該不存在了,所有引用計數應該比代碼塊內部少一個。
printf("4. Light ref count: %d. \n", ptr->getStrongCount());
// 將最後一個引用置空, 並且睡眠兩秒,等待看看這個對象會不會自動銷毀。
ptrOut = NULL;
printf("5. Light ref count: %d. \n", ptr->getStrongCount());
printf("Wre are going to sleep. \n");
sleep(2)
// 2s後我們直接退出程序
printf("Wre are going to exit. \n");
return 0;
}
大家先不用管具體的代碼細節是怎麼回事,先看看運行的結果。為了運行這個程序我們需要編譯它,這裡我把它編譯成android手機上可以運行的二進制文件,下面是Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := lightpointer
LOCAL_SRC_FILES := lightpointer.cpp
LOCAL_SHARED_LIBRAIES := \
libcutils \
libutils
include $(BUILD_EXECUTABLE)
可執行文件名稱就是lightpointer,並且存放於手機的system/bin下,以下是運行效果:
vcHLw7vT0KOsyseyu8rH09C140pBVkG1xNLiy7ywoT/KudPDuty88rWlyseyuz88L3A+DQo8cD7P1tTaztLDx8C0t9bO9tK7z8K41bLFtPrC69TZYW5kcm9pZM+1zbPE2reiyfrBy8qyw7SjrMrXz8jO0sPHv7TSu8/CTGlnaHRSZWZCYXNl1eK49sDgo6y0+sLrwre+tqO6L3N5c3RlbS9jb3JlL2luY2x1ZGUvdXRpbHMvUmVmQmFzZS5oPC9wPg0KPHA+y/y1xLT6wuvI58/CPC9wPg0KPHA+PGltZyBhbHQ9"這裡寫圖片描述" src="/uploadfile/Collfiles/20160624/20160624092928665.png" title="\" />
我們看到,這個類的實現還是比較簡答的,整體上公共方法就3個:
incStrong
decStrong
getStrongCount //剛才我們一直在用的方法
我們所有的目標類都應該是它的子類,首先我們應該看一下它的構造器。它的構造器是比較簡單的,只是將mCount這個變量初始化為0,從字面意思我們也可以看出這個變量就是表示實際的引用數目。並且我們剛才一直使用的getStrongCount方法也就是把它直接return了。接下來我們看到incStrong和decStrong兩個方法,從字面上可以看出來,這兩個方法分別是增加引用計數和減少引用計數。我們先看一下增加引用技術吧,他做的事情比較簡單,直接使用android的util函數庫中的android_atomic_inc來將mCount變量加1,這個函數的加1操作是原子操作,從名字上也可以看出,這是為了線程安全考慮的。然後我們再看一下減少引用技術的操作,這個也很簡單,首先使用android_atomic_dec這個原子操作函數將mCount減1,然後根據這個函數的返回值判斷是不是最後一個引用計數,如果是就直接delete這個對象,如果不是就跳過。這裡需要說明一下,android_atomic_dec這個函數的返回值是mCount減少之前的值相當於mCount–的值,所以這裡判斷的條件是1而不是0。但是現在我們有一個問題這些增加和減少引用計數的方法是哪裡調用的呢?還記得我們在上面那個代碼中的sp類嗎?對,就是它調用的!我們來看一下它的代碼:
它的代碼路徑:/system/core/include/utils/StrongPointer.h,代碼內容如下:
可以看到,它的內部方法基本很少,大部分都是運算符的重載。我們先看一下它的構造器:
首先,這個類是一個模板類,具體的對象類型是一個泛型。我們可以看到在它的構造器中將目標對象的引用賦值給m_ptr指針,然後如果目標對象的指針不為空的話直接調用它的incStrong方法將引用計數值加1。這是使用構造器傳遞指針的方式進行初始化的方式,我們上面的代碼並沒有使用這個方式,我們使用的是它的=號運算符重載:
可以看到這裡才是我們上面代碼使用的地方,這裡和構造器邏輯基本類似,也是直接調用incStrong方法將引用加1。這裡需要說明一下,這個方法考慮了sp指針重新賦值的情況,也就是說如果原本的m_ptr不為空,即原本是有指向的,現在需要先減少目標對象的引用計數,然後再將新的指針賦值給它。也就是說只要我們執行這條代碼:
sp ptrOut = ptr;
就會執行上面的代碼,然後引用計數就加1。相反如果我們把指針賦值為NULL或者別的值那麼目標對象的引用計數就會減少。
這樣一來,目標對象只要繼承自LightRefBase類,並且我們使用sp類指針對引用就能實現對象的自動銷毀,而不用再手動地執行delete了。
以上就是LightRefBase的分析,這是android的輕量級智能指針方案,實現和使用都比較簡單,代碼清爽不繁雜,這也就是他為什麼叫輕量級的原因。
如果說上面的LightRefBase是輕量級的,那麼RefBase就應該是重量級的了,它的名字中少了light。Android為神馬要引入這個類呢?想一下這樣一個場景,現在有兩個對象:A和B,對象A中有B的引用,因此B的引用等於1;對象B中有A的引用,因此對象A的引用對於1;現在問題來了,這兩個對象和外界的任何對象都沒有關系,也就說除了A和B兩者之間有關系,別人和他們都沒有關系!現在他們就是多余的了,應該被銷毀!但是由於A和B的引用計數都是1,不為0,因此使用我們上面的方案解決不了了!還是會有內存洩露問題!怎麼辦呢??解決的辦法是這樣的,將引用分類,分為兩類:強引用和弱引用。強引用就是我們上面使用的那種,弱引用是什麼呢?弱引用從字面上引用的力度比強引用要弱,事實確實是這樣。弱引用弱在哪裡呢?弱在保證使用對象的可靠性上。這麼說有點抽象,具體來說吧,像上面說的那個問題,如果A對象對B對象的引用是強引用的話,那麼B對象對A對象必須是弱引用,否則還有剛才說的循環引用的問題。對象的銷毀,關注的是對象的強引用,而不是對象的弱引用,也就是說如果對象的強引用為0的話不管對象的弱引用是多少直接delete掉!這就是弱引用弱的地方,也就是說你想使用的對象不一定存在呢!!另外,還有一個問題,那就是既然對象可能不存了,弱引用怎麼使用這個對象呢?面對這個問題,有這樣一個規定:
1. 弱引用在使用之前不如先升級為強引用才行。
如果對象不存在了,那麼升級弱引用是失敗的,自然就可以避免引用對象存在不確定性的問題了。說了這麼多,我們現在來分析一下RefBase的代碼,它的代碼和LightRefBase類存在於一個文件中:/system/core/include/utils/RefBase.h
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
//! DEBUGGING ONLY: Get current strong ref count.
int32_t getStrongCount() const;
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
// acquires a weak reference if there is already one.
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
// for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;
//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;
//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.
void trackMe(bool enable, bool retain);
};
weakref_type* createWeak(const void* id) const;
weakref_type* getWeakRefs() const;
//! DEBUGGING ONLY: Print references held on object.
inline void printRefs() const { getWeakRefs()->printRefs(); }
//! DEBUGGING ONLY: Enable tracking of object.
inline void trackMe(bool enable, bool retain)
{
getWeakRefs()->trackMe(enable, retain);
}
typedef RefBase basetype;
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
void extendObjectLifetime(int32_t mode);
//! Flags for onIncStrongAttempted()
enum {
FIRST_INC_STRONG = 0x0001
};
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
virtual void onLastWeakRef(const void* id);
private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
private:
friend class ReferenceMover;
static void renameRefs(size_t n, const ReferenceRenamer& renamer);
static void renameRefId(weakref_type* ref,
const void* old_id, const void* new_id);
static void renameRefId(RefBase* ref,
const void* old_id, const void* new_id);
weakref_impl* const mRefs;
};
這個看起來有些復雜,下面我們來一步一步分析它的實現。首先他和LightRefBase一樣,只是實現的功能不一樣而已,都是目標類的基類,你的目標類必須是這個類的子類。接下來我們以強指針和弱指針為兩條線路分析一下。
很多人剛開始看到sp的時候,都會以為sp是smart pointer的縮寫,其實不是他是strong pointer的縮寫。sp類的實現我們在前面分析LightRefBase類的時候已經分析過了,它的代碼還是比較簡單,主要就是一些運算符的重載。這裡我們重點分析一下RefBase和sp的協作。前面提到,sp類是一個模板類,它的目標類型可以是任何類,也就是說可以是LightRefBase類的子類,當然也可以是RefBase類的子類。我們看到RefBase類提供的方法比較多,我們先看下RefBase類也提供了incStrong和decStrong方法,並且還有getStrongCount調試方法這個和LightRefBase是一樣的。因此,在強指針這塊,LightRefBase和RefBase差別不是很大。
弱指針的實現才是重頭戲,畢竟弱指針的提出就是為了解決上面提到的循環引用的問題。在進一步分析RefBase之前,我們先看一下wp也就是弱指針的實現。弱指針的實現在:/system/core/include/utils/RefBase.h文件中:
template
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
wp(T* other);
wp(const wp& other);
wp(const sp& other);
template wp(U* other);
template wp(const sp& other);
template wp(const wp& other);
~wp();
// Assignment
wp& operator = (T* other);
wp& operator = (const wp& other);
wp& operator = (const sp& other);
template wp& operator = (U* other);
template wp& operator = (const wp& other);
template wp& operator = (const sp& other);
void set_object_and_refs(T* other, weakref_type* refs);
// promotion to sp
sp promote() const;
// Reset
void clear();
// Accessors
inline weakref_type* get_refs() const { return m_refs; }
inline T* unsafe_get() const { return m_ptr; }
// Operators
COMPARE_WEAK(==)
COMPARE_WEAK(!=)
COMPARE_WEAK(>)
COMPARE_WEAK(<)
COMPARE_WEAK(<=)
COMPARE_WEAK(>=)
inline bool operator == (const wp& o) const {
return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
}
template
inline bool operator == (const wp& o) const {
return m_ptr == o.m_ptr;
}
inline bool operator > (const wp& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
template
inline bool operator > (const wp& o) const {
return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
}
inline bool operator < (const wp& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
template
inline bool operator < (const wp& o) const {
return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
}
inline bool operator != (const wp& o) const { return m_refs != o.m_refs; }
template inline bool operator != (const wp& o) const { return !operator == (o); }
inline bool operator <= (const wp& o) const { return !operator > (o); }
template inline bool operator <= (const wp& o) const { return !operator > (o); }
inline bool operator >= (const wp& o) const { return !operator < (o); }
template inline bool operator >= (const wp& o) const { return !operator < (o); }
private:
template friend class sp;
template friend class wp;
T* m_ptr;
weakref_type* m_refs;
};
和強指針一樣,wp也是一個模板類,因為目標類的類型是不確定的。我們看到wp類提供的方法也不是很多,很多都是一些運算符的重載。我們先看一下構造器的實現:
template
wp::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
構造器中我們看到直接將目標對象的指針賦值給了m_ptr,然後就調用RefBase的createWeak方法:
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
這個方法直接調用weakref_type類對象的incWeak方法增加一個弱引用計數,那麼weakref_type類是什麼呢?我們可以看到RefBase類中提供了這個類,它是一個內部類:
class weakref_type
{
public:
RefBase* refBase() const;
void incWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
// acquires a weak reference if there is already one.
// This is not always safe. see ProcessState.cpp and BpBinder.cpp
// for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
int32_t getWeakCount() const;
//! DEBUGGING ONLY: Print references held on object.
void printRefs() const;
//! DEBUGGING ONLY: Enable tracking for this object.
// enable -- enable/disable tracking
// retain -- when tracking is enable, if true, then we save a stack trace
// for each reference and dereference; when retain == false, we
// match up references and dereferences and keep only the
// outstanding ones.
void trackMe(bool enable, bool retain);
};
這個類是實際表示引用計數的類,為什麼這麼說呢?我們看以下RefBase類的實現就知道了,RefBase的實現代碼:system/core/libutils/RefBase.cpp,這個代碼中有一個叫做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;
#if !DEBUG_REFS
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
, mFlags(0)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
, mRetain(false)
{
}
~weakref_impl()
{
bool dumpStack = false;
if (!mRetain && mStrongRefs != NULL) {
dumpStack = true;
ALOGE("Strong references remain:");
ref_entry* refs = mStrongRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.log(LOG_TAG);
#endif
refs = refs->next;
}
}
if (!mRetain && mWeakRefs != NULL) {
dumpStack = true;
ALOGE("Weak references remain!");
ref_entry* refs = mWeakRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.log(LOG_TAG);
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
CallStack stack(LOG_TAG);
}
}
void addStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "addStrongRef: RefBase=%p, id=%p", mBase, id);
addRef(&mStrongRefs, id, mStrong);
}
void removeStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "removeStrongRef: RefBase=%p, id=%p", mBase, id);
if (!mRetain) {
removeRef(&mStrongRefs, id);
} else {
addRef(&mStrongRefs, id, -mStrong);
}
}
void renameStrongRefId(const void* old_id, const void* new_id) {
//ALOGD_IF(mTrackEnabled,
// "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
// mBase, old_id, new_id);
renameRefsId(mStrongRefs, old_id, new_id);
}
void addWeakRef(const void* id) {
addRef(&mWeakRefs, id, mWeak);
}
void removeWeakRef(const void* id) {
if (!mRetain) {
removeRef(&mWeakRefs, id);
} else {
addRef(&mWeakRefs, id, -mWeak);
}
}
void renameWeakRefId(const void* old_id, const void* new_id) {
renameRefsId(mWeakRefs, old_id, new_id);
}
void trackMe(bool track, bool retain)
{
mTrackEnabled = track;
mRetain = retain;
}
void printRefs() const
{
String8 text;
{
Mutex::Autolock _l(mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mStrongRefs);
sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
printRefsLocked(&text, mWeakRefs);
}
{
char name[100];
snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
write(rc, text.string(), text.length());
close(rc);
ALOGD("STACK TRACE for %p saved in %s", this, name);
}
else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
name, strerror(errno));
}
}
private:
struct ref_entry
{
ref_entry* next;
const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED
CallStack stack;
#endif
int32_t ref;
};
void addRef(ref_entry** refs, const void* id, int32_t mRef)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = new ref_entry;
// Reference count at the time of the snapshot, but before the
// update. Positive value means we increment, negative--we
// decrement the reference count.
ref->ref = mRef;
ref->id = id;
#if DEBUG_REFS_CALLSTACK_ENABLED
ref->stack.update(2);
#endif
ref->next = *refs;
*refs = ref;
}
}
void removeRef(ref_entry** refs, const void* id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* const head = *refs;
ref_entry* ref = head;
while (ref != NULL) {
if (ref->id == id) {
*refs = ref->next;
delete ref;
return;
}
refs = &ref->next;
ref = *refs;
}
ALOGE("RefBase: removing id %p on RefBase %p"
"(weakref_type %p) that doesn't exist!",
id, mBase, this);
ref = head;
while (ref) {
char inc = ref->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
ref = ref->next;
}
CallStack stack(LOG_TAG);
}
}
void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
ref_entry* ref = r;
while (ref != NULL) {
if (ref->id == old_id) {
ref->id = new_id;
}
ref = ref->next;
}
}
}
void printRefsLocked(String8* out, const ref_entry* refs) const
{
char buf[128];
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
sprintf(buf, "\t%c ID %p (ref %d):\n",
inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
out->append(refs->stack.toString("\t\t"));
#else
out->append("\t\t(call stacks disabled)");
#endif
refs = refs->next;
}
}
mutable Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;
bool mTrackEnabled;
// Collect stack traces on addref and removeref, instead of deleting the stack references
// on removeref that match the address ones.
bool mRetain;
#endif
};
這個類的代碼有點長,其實我們仔細看一下大部分都是DEBUG_REFS等宏控制的調試代碼,我們分析的時候可以直接跳過,除了這些代碼剩下的基本就是這些了:
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)
, mWeak(0)
, mBase(base)
, mFlags(0)
{
}
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
}
很精簡是吧?我們看到weakref_impl類是weakref_type類的子類,並且在release版本中那些調試函數的實現全部是空的,主要就是這個類中的幾個成員變量需要我們關注:
volatile int32_t mStrong;
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
從名稱也可以看出來,第一個是強引用計數,第二個是弱引用計數,第三個是一個指向RefBase類的指針,這個指針實際指向的是目標類的對象,因為目標類是RefBase類的子類,第四個是標志位,這個標志位主要用來管理對象的生命周期的,這個後面會說明。其實這裡的weakref_impl就相當於LightRefBase裡面的mCount,只是我們這裡的RefBase需要管理強指針和弱指針,一個變量肯定是不行的,所以這裡需要一個類來表示才行。
現在看來,wp,RefBase,weakref_impl類的關系有點亂,不太好理解,我們看一下下面的圖:
其中wp是操作的指針類,這個類中包含指向RefBase實際目標子類對象的指針和一個指向weakref_impl類對象的指針;RefBase類包含了一個指向weakref_impl類對象的一個指針,用來管理引用計數;weakref_impl類就是實際的計數器,這個裡面也包含了RefBase類子類的對象指針,另外,它是weakref_type類的子類。這些關系,需要讀者認真理解參悟之前給出的代碼才能弄明白的,一言半語只能明白個大概。
接下來的重點就是弄明白這幾個類是怎麼實現計數管理的目標的。之前我們說到了createWeak這個方法,這個方法直接調用了weakref_type類的incWeak方法,incWeak方法定義如下:
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast(this);
impl->addWeakRef(id);
const int32_t c __unused = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
可以看到最終調用了android_atomic_inc這個原子操作函數將weakref_impl類對象的mWeak變量增加了1。到這裡我們就明白了在構造器中是怎麼實現弱引用計數的管理的了。現在我們再看一下=號運算符重載部分的操作:
template
wp& wp::operator = (T* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
return *this;
}
基本邏輯還是一樣的,先看目標對象的指針是不是空,如果不是空就調用createWeak,然後如果m_ptr不為空的話,也就是先前有指向那就先decWeak,釋放弱引用計數,然後在將目標對象指針和weakref_type對象指針賦值。這一點和強指針的操作是一樣的。
這裡我們就基本分析完了弱引用計數的管理過程,但是之前說到,弱指針想要使用目標對象的方法,就必須將弱指針升級為強指針。那麼怎麼升級呢?前面我們在看wp類的定義時不知道大家有沒有注意到這個方法:
// promotion to sp
sp promote() const;
是的,就是這個方法,從字面意思上看,這個方法就是將弱指針升級為強指針的方法。我們看一下這個方法的實現:
template
sp wp::promote() const
{
sp result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
可以看到這裡的操作就是通過weakref_type類的attemptIncStrong方法來獲得強指針應用,attemptIncStrong方法定義如下:
bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
incWeak(id);
weakref_impl* const impl = static_cast(this);
int32_t curCount = impl->mStrong;
ALOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow", this);
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
// we're in the easy/common case of promoting a weak-reference
// from an existing strong reference.
if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation.
curCount = impl->mStrong;
}
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we're now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong'ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
} else {
// this object has an "extended" life-time, i.e.: it can be
// revived from a weak-reference only.
// Ask the object's implementation if it agrees to be revived
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
// it didn't so give-up.
decWeak(id);
return false;
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
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 PRINT_REFS
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
// now we need to fix-up the count if it was INITIAL_STRONG_VALUE
// this must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
curCount = impl->mStrong;
while (curCount >= INITIAL_STRONG_VALUE) {
ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
"attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
this);
if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
&impl->mStrong) == 0) {
break;
}
// the strong-count changed on us, we need to re-assert the situation,
// for e.g.: it's possible the fix-up happened in another thread.
curCount = impl->mStrong;
}
return true;
}
這個方法比較長,我們一步步來分析下。首先如果目前的強引用計數不為0,並且不等於INITIAL_STRONG_VALUE(這個值是強引用計數的初始化的值)的話,這個情況也就是正常情況下,說明這個時候目標對象已經存了一個強引用,這個時候我們就直接調用android_atomic_cmpxchg函數將mStrong變量增加1,android_atomic_cmpxchg這個函數的定義如下:
android_atomic_cmpxchg(oldValue, newValue, addr)
這個函數的功能就是當oldValue的值和addr地址中的值一樣的時候,就將newValue的值賦值給addr地址中的變量。我們這個地方的調用的目的就是,如果這個時候mStrong的值和我們之前獲得的curCount值一樣的話,就吧mStrong的值增加1,然後返回0,否則非0.這一步就是將強引用的值增加1,因為我們需要升級為強引用了。接下來就是判斷curCount也就是目標對象的強引用的值了,會檢查這個值是不是小於等於0或者等於它的初始值,這裡的意思是如果目標對象的強引用全部被釋放了,或者壓根就沒有被任何人引用過的話,就執行判斷裡面的代碼,這顯然是一種少數情況。我們看一下他裡面的代碼(上面已經貼出,這裡截取片段,以便分析):
if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we're now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong'ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
} else {
// this object has an "extended" life-time, i.e.: it can be
// revived from a weak-reference only.
// Ask the object's implementation if it agrees to be revived
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
// it didn't so give-up.
decWeak(id);
return false;
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
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);
}
}
前面我們提到了目標對象的生命周期的事情,這裡就要涉及到了。首先,我們看一下目標對象都有那些生命周期,生命周期定義如下(定義在RefBase類中):
//! Flags for extendObjectLifetime()
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
從注釋中我們也可以看出來,這些生命周期枚舉變量其實是標示再mFlag變量中的,並且可以使用extendObjectLifetime方法設置的:
void extendObjectLifetime(int32_t mode);
這個方法就是用戶可以手動設置目標對象的生命周期的。現在我們來解釋一下生命周期的含義,為了說明它的含義我們看一下強引用和弱引用減少時的銷毀對象的策略就明白了,先看一下強引用的減少方法:
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);
const int32_t c = android_atomic_dec(&refs->mStrong);
#if PRINT_REFS
ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
refs->mBase->onLastStrongRef(id);
if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
delete this;
}
}
refs->decWeak(id);
}
這裡我們看到首先是將強引用計數減少1,然後判斷這是不是最後的一個引用,如果是的話,那就回調目標對象的onLastStrongRef方法,通知目前是最後一個強引用這個對象可能要被銷毀了。然後就是判斷它的生命周期標識是不是OBJECT_LIFETIME_STRONG,如果是就銷毀,如果不是就跳過。我們再看一下弱引用的減少方法:
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast(this);
impl->removeWeakRef(id);
const int32_t c = android_atomic_dec(&impl->mWeak);
ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return;
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 {
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete 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;
}
}
}
我們看到,基本邏輯還是先減少弱引用計數的值,然後判斷是不是最後一個弱引用,如果是就繼續下面的代碼,如果不是就直接返回。我們看一下如果是最後一個引用的情況,判斷的依據還是目標對象的生命周期標識,如果是OBJECT_LIFETIME_STRONG的話,還要判斷目前強引用計數是不是初始值也就是是不是壓根就沒有人引用它,如果是就直接銷毀這個對象,如果不是就銷毀目前的計數器類,也就是weakref_impl類的對象,然後強引用技術自然會由於指向的類被銷毀就減少1,對象銷毀由強引用管理完成。這是對象的生命周期標識是OBJECT_LIFETIME_STRONG的情況,如果對象的生命周期標識是其他的話,我們看到上面定義的生命周期標識中只有兩個,但是這裡的注釋中提到了FOREVER標識,其實我們看下面的代碼知道了,下面直接判斷對象的生命周期標識是不是OBJECT_LIFETIME_WEAK,如果是就直接銷毀對象,如果不是就什麼也不做了。其實這裡不會有別的情況,因為google定義的OBJECT_LIFETIME_MASK之判斷flag的第一位,是0就是strong,1就是weak!!但是奇怪的是這裡的注釋提到了OBJECT_LIFETIME_{WEAK|FOREVER}這兩個標識位,個人認為這可能是google的代碼注釋有問題的地方,可能以前老的版本中有這個定義但是現在新的版本中沒有了,但是這個標識為沒有刪除!!因為我在這裡分析的代碼是6.0.1的這個版本中確實沒有OBJECT_LIFETIME_FOREVER標識的定義,但是我在2.2.3版本找到這個定義,同時也證實了我們上面的猜想,google確實應該把這裡的注釋修改一下,以免使人誤會呀!!!!
解釋了生命周期方法之後我們繼續看上面弱指針升級的代碼,這裡我們看到:
if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
if (android_atomic_cmpxchg(curCount, curCount + 1,
&impl->mStrong) == 0) {
break;
}
// the strong count has changed on us, we need to re-assert our
// situation (e.g.: another thread has inc/decStrong'ed us)
curCount = impl->mStrong;
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
decWeak(id);
return false;
}
}
首先判斷是不是OBJECT_LIFETIME_STRONG標識,如果是的話,那就先判斷強引用技術是不是小於等於0,也就是是不是所有的強引用都全部釋放了,如果是的話,就減少弱引用然後直接返回false表示升級失敗。當強引用計數大於0的時候,我們就先增加強引用技術,使用的方法和前面一樣。最後,我們還要看一下目標對象的引用計數是不是小於等於0,如果是就直接減少弱引用計數,然後返回false。最後為什麼還要判斷引用計數呢?這裡的注釋已經解釋了,因為對象有可能會在多線程中使用,可能在我們操作的同時就有線程把最後一個強引用釋放了,這個時候對象已經被銷毀了,因此這裡我們需要檢查一些,保證線程安全。
如果目標對象的生命周期標識是其他的話,也就是說是OBJECT_LIFETIME_WEAK的話,我們就回調目標對象的onIncStrongAttempted方法請求是不是允許在這種情況下升級指針,如果返回true表示允許,如果返回false表示不允許。這個方法目標對象類可以實現也可以實現,如果不實現的話就使用父類的定義:
bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
{
return (flags&FIRST_INC_STRONG) ? true : false;
}
可以看到父類的實現比較簡單,如果給的flag參數是FIRST_INC_STRONG的話,也就是是第一次強升級引用的話,那就允許,正好我們上面傳遞進來的參數就是這個,所以這樣的話,如果目標對象類沒有實現這個方法的話,升級操作總是允許的!這點需要明白的。如果目標對象不想允許這個時候的操作,那就實現這個方法,並且根據flag返回false就好了。繼續我們的分析,如果允許這個時候的升級那就將強引用增加1.
接下來我們判斷目前的強引用計數是不是在0~INITIAL_STRONG_VALUE之間也就是正常值范圍內,因為我們這裡的大前提條件就是目標對象沒有被人引用過,因此這裡需要回調onLastStrongRef方法,通知目標對象。
接下來的代碼就比較簡單了:
impl->addStrongRef(id);
#if PRINT_REFS
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
// now we need to fix-up the count if it was INITIAL_STRONG_VALUE
// this must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
curCount = impl->mStrong;
while (curCount >= INITIAL_STRONG_VALUE) {
ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
"attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
this);
if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
&impl->mStrong) == 0) {
break;
}
// the strong-count changed on us, we need to re-assert the situation,
// for e.g.: it's possible the fix-up happened in another thread.
curCount = impl->mStrong;
}
return true;
首先我們把這個強引用指針添加到強引用中去,但是我們前面分析說,在release版本中addStrongRef方法實現是空的,因此這一步跳過,它是調試使用的。接下來,我們先獲得最新的強引用計數,然後判斷mStrong的值是不是比INITIAL_STRONG_VALUE要大,有人會問,怎麼會比這個值大呢?他不是強引用的最大值嗎?是的,這個值既是最大值也是初始值,我們再來仔細看一下強引用增加部分的代碼:
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id);
refs->addStrongRef(id);
const int32_t c = android_atomic_inc(&refs->mStrong);
ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
#if PRINT_REFS
ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
if (c != INITIAL_STRONG_VALUE) {
return;
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();
}
注意這裡的操作,首先是:
const int32_t c = android_atomic_inc(&refs->mStrong);
如果是第一次引用,然後就是:
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
第一次執行之後強引用的值是在初始值的基礎上增加了1,也就是說這個時候的值已經比INITIAL_STRONG_VALUE大了,然後才執行android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);給它減去初始值才是最後的1.但是麻煩的是這裡的兩個操作並不是原子的,也就是說可能被打斷,因此我們的attemptIncStrong方法最後才需要做出那個看似奇怪的判斷,其實google的注釋部分已經解釋了這個問題了,大家可以看一下。attemptIncStrong函數的最後就直接返回true表示升級成功。這個時候我們返回來看我們的promote代碼:
template
sp wp::promote() const
{
sp result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
如果attemptIncStrong返回為true的話,就吧result這個sp中的目標對象指針設置成現有的對象指針,以便sp指針操作這個對象;如果attemptIncStrong返回false的話,那就不會設置這個對象指針,那就是說sp的對象操作會發生段錯誤!!你在操作之前一定要調用sp的get()方法判斷是不是確實升級成功了,get()方法定義:
inline T* get() const
{
return m_ptr;
}
到這裡為止,我們就分析完了弱指針的升級過程。
這裡我給出一個demo代碼,展示一下sp,wp和RefBase怎麼使用,首先看下代碼:
/*************************************************************************
> File Name: strongpointer.cpp
> Author: Baniel Gao
> Mail: [email protected]
> Created Time: Wed 22 Jun 2016 09:04:38 AM CST
************************************************************************/
#include
#include
#include
using namespace android;
class StrongClass : public RefBase
{
public:
StrongClass()
{
printf("create an instance of StrongClass. \n");
}
virtual ~StrongClass()
{
printf("destory an instance of StrongClass \n");
}
void onFirstRef()
{
printf("StrongClass onFirstRef \n");
}
void onLastStrongRef(const void* id)
{
printf("StrongClass onLastStrongRef \n");
}
bool onIncStrongAttempted(uint32_t flags, const void* id)
{
printf("StrongClass onIncStrongAttempted \n");
return true;
}
void onLastWeakRef(const void* id)
{
printf("StrongClass onLastWeakRef \n");
}
};
class WeakClass : public RefBase
{
public:
WeakClass()
{
// 設置生命周期標識位
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
printf("create an instance of WeakClass \n");
}
virtual ~WeakClass()
{
printf("destory an instance of WeakClass \n");
}
void onFirstRef()
{
printf("WeakClass onFirstRef \n");
}
void onLastStrongRef(const void* id)
{
printf("WeakClass onLastStrongRef \n");
}
bool onIncStrongAttempted(uint32_t flags, const void* id)
{
printf("WeakClass onIncStrongAttempted \n");
return true;
}
void onLastWeakRef(const void* id)
{
printf("WeakClass onLastWeakRef \n");
}
};
int main(int argc, char** argv)
{
printf("####################strong class test start#################### \n");
sp sp_ptr_1 = new StrongClass();
sp sp_ptr_2 = sp_ptr_1;
wp wp_ptr_1 = sp_ptr_1;
wp wp_ptr_2 = sp_ptr_1;
printf("1. strong class strong refs: %d \n", sp_ptr_1->getStrongCount());
printf("2. strong class weak refs: %d \n", wp_ptr_1.get_refs()->getWeakCount());
sp_ptr_2 = NULL;
printf("3. strong class strong refs: %d \n", sp_ptr_1->getStrongCount());
wp_ptr_2 = NULL;
printf("4. strong class weak refs: %d \n", wp_ptr_1.get_refs()->getWeakCount());
printf("5. strong class strong refs: %d \n", wp_ptr_1.promote()->getStrongCount());
printf("6. we are going to release all weak refs!! \n");
wp_ptr_1 = NULL;
printf("7. we are going to release all strong refs!! \n");
sp_ptr_1 = NULL;
printf("####################strong class test end#################### \n");
printf("####################weak class test start#################### \n");
sp sp_ptr_3 = new WeakClass();
sp sp_ptr_4 = sp_ptr_3;
wp wp_ptr_3 = sp_ptr_3;
wp wp_ptr_4 = sp_ptr_3;
printf("1. weak class strong refs: %d \n", sp_ptr_3->getStrongCount());
printf("2. weak class weak refs: %d \n", wp_ptr_3.get_refs()->getWeakCount());
sp_ptr_4 = NULL;
printf("3. weak class strong refs: %d \n", sp_ptr_3->getStrongCount());
wp_ptr_4 = NULL;
printf("4. weak class weak refs: %d \n", wp_ptr_3.get_refs()->getWeakCount());
printf("5. weak class strong refs: %d \n", wp_ptr_3.promote()->getStrongCount());
printf("6. we are going to release all strong refs!! \n");
sp_ptr_3 = NULL;
printf("7. we are going to release all weak refs!! \n");
wp_ptr_3 = NULL;
printf("####################weak class test end#################### \n");
return 0;
}
Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := strongpointer
LOCAL_SRC_FILES := strongpointer.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils
include $(BUILD_EXECUTABLE)
上面程序的運行結果如下:
結果是完全符合我們預期的,這裡我們看到在WeakClass中實現了釋放全部強引用而對象不被銷毀,直到所有的弱引用被釋放之後才被銷毀!!其余的結果,讀者可以結合上面我們的講解,自己分析一下上面程序的輸出為什麼是這樣的。
Android Studio代碼著色插件 前言:半個多月沒寫博客了,放了個假期,這人才緩過來神,懶的啥都不想干,可算是明白一句話的意思了:玩物喪志啊!好在公司項
在這篇文章中Android React Native的使用細節問題提到了 圖片使用的問題,也提到了無論用哪種方法都不能加載app內部的圖片資源的問題,當時的代碼是這樣子的
上一篇文章介紹了MediaPlayer相關內容,這次用兩篇文章來介紹SurfaceView的用法。網上介紹SurfaceView的用法有很多,寫法也層出不同,例如繼承Su
什麼是變量?在計算機中用來存儲信息,通過聲明語句來指明存儲位置和所需空間。變量的聲明方法及賦值分號:語句結束標志 賦值號:將=右邊的值賦給左邊的變量變量有哪些數據類型?變
Agenda:一張圖看Camera2框架類圖 CameraService