Android系统的运行时库层代码是用C++来编写的,用C++来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统 崩溃。不过系统为我们提供了智能指针,避免出现上述问题,本文将系统地分析Android系统智能指针(轻量级指针、强指针和弱指针)的实现原理。
老罗参加了“CSDN2013博客之星评选活动”,欢迎大家投票支持!
在使用C++来编写代码的过程中,指针使用不当造成内存泄漏一般就是因为new了一个对象并且使用完之后,忘记了delete这个对象,而造成系统崩溃 一般就是因为一个地方delete了这个对象之后,其它地方还在继续使原来指向这个对象的指针。为了避免出现上述问题,一般的做法就是使用引用计数的方 法,每当有一个指针指向了一个new出来的对象时,就对这个对象的引用计数增加1,每当有一个指针不再使用这个对象时,就对这个对象的引用计数减少1,每 次减1之后,如果发现引用计数值为0时,那么,就要delete这个对象了,这样就避免了忘记delete对象或者这个对象被delete之后其它地方还 在使用的问题了。但是,如何实现这个对象的引用计数呢?肯定不是由开发人员来手动地维护了,要开发人员时刻记住什么时候该对这个对象的引用计数加1,什么 时候该对这个对象的引用计数减1,一来是不方便开发,二来是不可靠,一不小心哪里多加了一个1或者多减了一个1,就会造成灾难性的后果。这时候,智能指针 就粉墨登场了。首先,智能指针是一个对象,不过这个对象代表的是另外一个真实使用的对象,当智能指针指向实际对象的时候,就是智能指针对象创建的时候,当 智能指针不再指向实际对象的时候,就是智能指针对象销毁的时候,我们知道,在C++中,对象的创建和销毁时会分别自动地调用对象的构造函数和析构函数,这 样,负责对真实对象的引用计数加1和减1的工作就落实到智能指针对象的构造函数和析构函数的身上了,这也是为什么称这个指针对象为智能指针的原因。
在计算机科学领域中,提供垃圾收集(Garbage Collection)功能的系统框架,即提供对象托管功能的系统框架,例如Java应用程序框架,也是采用上述的引用计数技术方案来实现的,然而,简单 的引用计数技术不能处理系统中对象间循环引用的情况。考虑这样的一个场景,系统中有两个对象A和B,在对象A的内部引用了对象B,而在对象B的内部也引用 了对象A。当两个对象A和B都不再使用时,垃圾收集系统会发现无法回收这两个对象的所占据的内存的,因为系统一次只能收集一个对象,而无论系统决定要收回 对象A还是要收回对象B时,都会发现这个对象被其它的对象所引用,因而就都回收不了,这样就造成了内存泄漏。这样,就要采取另外的一种引用计数技术了,即 对象的引用计数同时存在强引用和弱引用两种计数,例如,Apple公司提出的框 架,当父对象要引用子对象时,就对子对象使用强引用计数技术,而当子对象要引用父对象时,就对父对象使用弱引用计数技术,而当垃圾收集系统执行对象回收工 作时,只要发现对象的强引用计数为0,而不管它的弱引用计数是否为0,都可以回收这个对象,但是,如果我们只对一个对象持有弱引用计数,当我们要使用这个 对象时,就不直接使用了,必须要把这个弱引用升级成为强引用时,才能使用这个对象,在转换的过程中,如果对象已经不存在,那么转换就失败了,这时候就说明 这个对象已经被销毁了,不能再使用了。
了解了这些背景知识后,我们就可以进一步学习Android系统的智能指针的实现原理了。Android系统提供了强大的智能指针技术供我们使用,这些智 能指针实现方案既包括简单的引用计数技术,也包括了复杂的引用计数技术,即对象既有强引用计数,也有弱引用计数,对应地,这三种智能指针分别就称为轻量级 指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Weak Pointer)。无论是轻量级指针,还是强指针和弱指针,它们的实现框架都是一致的,即由对象本身来提供引用计数器,但是它不会去维护这个引用计数器的 值,而是由智能指针来维护,就好比是对象提供素材,但是具体怎么去使用这些素材,就交给智能指针来处理了。由于不管是什么类型的对象,它都需要提供引用计 数器这个素材,在C++中,我们就可以把这个引用计数器素材定义为一个公共类,这个类只有一个成员变量,那就是引用计数成员变量,其它提供智能指针引用的 对象,都必须从这个公共类继承下来,这样,这些不同的对象就天然地提供了引用计数器给智能指针使用了。总的来说就是我们在实现智能指会的过程中,第一是要 定义一个负责提供引用计数器的公共类,第二是我们要实现相应的智能指针对象类,后面我们会看到这种方案是怎么样实现的。
接下来,我们就先介绍轻量级指针的实现原理,然后再接着介绍强指针和弱指针的实现原理。
1. 轻量级指针
先来看一下实现引用计数的类LightRefBase,它定义在frameworks/base/include/utils/RefBase.h文件中:
- template <class T>
- class LightRefBase
- {
- public:
- inline LightRefBase() : mCount(0) { }
- inline void incStrong(const void* id) const {
- android_atomic_inc(&mCount);
- }
- inline void decStrong(const void* id) const {
- if (android_atomic_dec(&mCount) == 1) {
- delete static_cast<const T*>(this);
- }
- }
- //! DEBUGGING ONLY: Get current strong ref count.
- inline int32_t getStrongCount() const {
- return mCount;
- }
- protected:
- inline ~LightRefBase() { }
- private:
- mutable volatile int32_t mCount;
- };
前面说过,要实现自动引用计数,除了要有提供引用计数器的基类外,还需要有智能指针类。在Android系统中,配合LightRefBase引用计数使 用的智能指针类便是sp了,它也是定义在frameworks/base/include/utils/RefBase.h文件中:
- template <typename T>
- class sp
- {
- public:
- typedef typename RefBase::weakref_type weakref_type;
- inline sp() : m_ptr(0) { }
- sp(T* other);
- sp(const sp<T>& other);
- template<typename U> sp(U* other);
- template<typename U> sp(const sp<U>& other);
- ~sp();
- // Assignment
- sp& operator = (T* other);
- sp& operator = (const sp<T>& other);
- template<typename U> sp& operator = (const sp<U>& other);
- template<typename U> sp& operator = (U* other);
- //! Special optimization for use by ProcessState (and nobody else).
- void force_set(T* other);
- // Reset
- void clear();
- // Accessors
- inline T& operator* () const { return *m_ptr; }
- inline T* operator-> () const { return m_ptr; }
- inline T* get() const { return m_ptr; }
- // Operators
- COMPARE(==)
- COMPARE(!=)
- COMPARE(>)
- COMPARE(<)
- COMPARE(<=)
- COMPARE(>=)
- private:
- template<typename Y> friend class sp;
- template<typename Y> friend class wp;
- // Optimization for wp::promote().
- sp(T* p, weakref_type* refs);
- T* m_ptr;
- };
- template<typename T>
- sp<T>::sp(T* other)
- : m_ptr(other)
- {
- if (other) other->incStrong(this);
- }
- template<typename T>
- sp<T>::sp(const sp<T>& other)
- : m_ptr(other.m_ptr)
- {
- if (m_ptr) m_ptr->incStrong(this);
- }
最后,看一下析构函数:
- template<typename T>
- sp<T>::~sp()
- {
- if (m_ptr) m_ptr->decStrong(this);
- }
轻量级智能指针的实现原理大概就是这样了,比较简单,下面我们再用一个例子来说明它的用法。
2. 轻量级指针的用法
参考一文,我们在external目录下建立一个C++工程目录lightpointer,它里面有两个文件,一个lightpointer.cpp文件,另外一个是Android.mk文件。
源文件lightpointer.cpp的内容如下:
- #include <stdio.h>
- #include <utils/RefBase.h>
- using namespace android;
- class LightClass : public LightRefBase<LightClass>
- {
- public:
- LightClass()
- {
- printf("Construct LightClass Object.");
- }
- virtual ~LightClass()
- {
- printf("Destory LightClass Object.");
- }
- };
- int main(int argc, char** argv)
- {
- LightClass* pLightClass = new LightClass();
- sp<LightClass> lpOut = pLightClass;
- printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
- {
- sp<LightClass> lpInner = lpOut;
- printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
- }
- printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());
- return 0;
- }
编译脚本文件Android.mk的内容如下:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := lightpointer
- LOCAL_SRC_FILES := lightpointer.cpp
- LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils
- include $(BUILD_EXECUTABLE)
- USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer
- USER-NAME@MACHINE-NAME:~/Android$ make snod
- USER-NAME@MACHINE-NAME:~/Android$ adb shell
- root@android:/ # cd system/bin/
- root@android:/system/bin # ./lightpointer
- Construct LightClass Object.
- Light Ref Count: 1.
- Light Ref Count: 2.
- Light Ref Count: 1.
- Destory LightClass Object.
这里可以看出,程序一切都是按照我们的设计来运行,这也验证了我们上面分析的轻量级智能指针的实现原理。
3. 强指针
强指针所使用的引用计数类为RefBase,它LightRefBase类要复杂多了,所以才称后者为轻量级的引用计数基类吧。我们先来看看 RefBase类的实现,它定义在frameworks/base/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);
- bool attemptIncStrong(const void* id);
- //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
- 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);
- }
- protected:
- RefBase();
- virtual ~RefBase();
- //! Flags for extendObjectLifetime()
- enum {
- OBJECT_LIFETIME_WEAK = 0x0001,
- OBJECT_LIFETIME_FOREVER = 0x0003
- };
- 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);
- weakref_impl* const mRefs;
- };
RefBase类的成员变量mRefs的类型为weakref_impl指针,它实现在frameworks/base/libs/utils/RefBase.cpp文件中:
- 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 addWeakRef(const void* /*id*/) { }
- void removeWeakRef(const void* /*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)
- {
- //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
- }
- ~weakref_impl()
- {
- LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
- LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
- }
- void addStrongRef(const void* id)
- {
- addRef(&mStrongRefs, id, mStrong);
- }
- void removeStrongRef(const void* id)
- {
- if (!mRetain)
- removeRef(&mStrongRefs, id);
- else
- addRef(&mStrongRefs, id, -mStrong);
- }
- 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 trackMe(bool track, bool retain)
- {
- mTrackEnabled = track;
- mRetain = retain;
- }
- ......
- 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* ref = *refs;
- while (ref != NULL) {
- if (ref->id == id) {
- *refs = ref->next;
- delete ref;
- return;
- }
- refs = &ref->next;
- ref = *refs;
- }
- LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
- id, mBase, this);
- }
- }
- ......
- 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
- };
- #if !DEBUG_REFS
- ......
- #else
- #else
- ......
- #endif
- struct ref_entry
- {
- ref_entry* next;
- const void* id;
- #if DEBUG_REFS_CALLSTACK_ENABLED
- CallStack stack;
- #endif
- int32_t ref;
- };
总的来说,weakref_impl类只要提供了以下四个成员变量来维护对象的引用计数:
- volatile int32_t mStrong;
- volatile int32_t mWeak;
- RefBase* const mBase;
- volatile int32_t mFlags;
- //! Flags for extendObjectLifetime()
- enum {
- OBJECT_LIFETIME_WEAK = 0x0001,
- OBJECT_LIFETIME_FOREVER = 0x0003
- };
说了这多,RefBase类给人的感觉还是挺复杂的,不要紧,我们一步步来,先通过下面这个图来梳理一下这些类之间的关系:
从这个类图可以看出,每一个RefBase对象包含了一个weakref_impl对象,而weakref_impl对象实现了 weakref_type接口,同时它可以包含多个ref_entry对象,前面说过,ref_entry是调试用的一个结构体,实际使用中可以不关注。
提供引用计数器的类RefBase我们就暂时介绍到这里,后面我们再结合智能指针类一起分析,现在先来看看强指针类和弱指针类的定义。强指针类的定义我 们在前面介绍轻量级指针的时候已经见到了,就是sp类了,这里就不再把它的代码列出来了。我们来看看它的构造函数的实现:
- template<typename T>
- sp<T>::sp(T* other)
- : m_ptr(other)
- {
- if (other) other->incStrong(this);
- }
这里传进来的参数other一定是继承于RefBase类的,因此,在函数的内部,它调用的是RefBase类的incStrong函数,它定义在frameworks/base/libs/utils/RefBase.cpp文件中:
- void RefBase::incStrong(const void* id) const
- {
- weakref_impl* const refs = mRefs;
- refs->addWeakRef(id);
- refs->incWeak(id);
- refs->addStrongRef(id);
- const int32_t c = android_atomic_inc(&refs->mStrong);
- LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
- #if PRINT_REFS
- LOGD("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);
- const_cast<RefBase*>(this)->onFirstRef();
- }
- RefBase::RefBase()
- : mRefs(new weakref_impl(this))
- {
- // LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
- }
一是增加弱引用计数:
- refs->addWeakRef(id);
- refs->incWeak(id);
- refs->addStrongRef(id);
- const int32_t c = android_atomic_inc(&refs->mStrong);
- if (c != INITIAL_STRONG_VALUE) {
- return;
- }
- android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
- const_cast<RefBase*>(this)->onFirstRef();
- #define INITIAL_STRONG_VALUE (1<<28)
回过头来看弱引用计数是如何增加的,首先是调用weakref_impl类的addWeakRef函数,我们知道,在Release版本中,这个函数也 不做,而在Debug版本中,这个函数增加了一个ref_entry对象到了weakref_impl对象的mWeakRefs列表中,表示此 weakref_impl对象的弱引用计数被增加了一次。接着又调用了weakref_impl类的incWeak函数,真正增加弱引用计数值就是在这个 函数实现的了,weakref_impl类的incWeak函数继承于其父类weakref_type的incWeak函数:
- void RefBase::weakref_type::incWeak(const void* id)
- {
- weakref_impl* const impl = static_cast<weakref_impl*>(this);
- impl->addWeakRef(id);
- const int32_t c = android_atomic_inc(&impl->mWeak);
- LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
- }
- const int32_t c = android_atomic_inc(&impl->mWeak);
Ah I see. Well the debug code may be broken, though I wouldn't leap to that conclusion without actually testing it; I know it has been used in the past. Anyway, these things get compiled out in non-debug builds, so there is no reason to change them unless you are actually trying to use this debug code and it isn't working and need to do this to fix it.
既然他也不知道怎么回事,我们也不必深究了,知道有这么回事就行。
这里总结一下强指针类sp在其构造函数里面所做的事情就是分别为目标对象的强引用计数和弱引和计数增加了1。
再来看看强指针类的析构函数的实现:
- template<typename T>
- sp<T>::~sp()
- {
- if (m_ptr) m_ptr->decStrong(this);
- }
- 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
- LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
- #endif
- LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
- if (c == 1) {
- const_cast<RefBase*>(this)->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- delete this;
- }
- }
- refs->removeWeakRef(id);
- refs->decWeak(id);
- }
- const int32_t c = android_atomic_dec(&refs->mStrong);
- if (c == 1) {
- const_cast<RefBase*>(this)->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- delete this;
- }
- }
接下来的ref->removeWeakRef函数调用语句是对应前面在RefBase::incStrong函数里的refs->addWeakRef函数调用语句的,在Release版本中,这也是一个空实现函数,真正实现强引用计数减1的操作下面的refs->decWeak函数,weakref_impl类没有实现自己的decWeak函数,它继承了weakref_type类的decWeak函数:
- void RefBase::weakref_type::decWeak(const void* id)
- {
- weakref_impl* const impl = static_cast<weakref_impl*>(this);
- impl->removeWeakRef(id);
- const int32_t c = android_atomic_dec(&impl->mWeak);
- LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
- if (c != 1) return;
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- if (impl->mStrong == INITIAL_STRONG_VALUE)
- delete impl->mBase;
- else {
- // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
- delete impl;
- }
- } else {
- impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
- delete impl->mBase;
- }
- }
- }
- const int32_t c = android_atomic_dec(&impl->mWeak);
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- if (impl->mStrong == INITIAL_STRONG_VALUE)
- delete impl->mBase;
- else {
- // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
- delete impl;
- }
- } else {
- impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
- delete impl->mBase;
- }
- }
- if (impl->mStrong == INITIAL_STRONG_VALUE)
- delete impl->mBase;
- else {
- // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
- delete impl;
- }
如果是前一种场景,这里的impl->mStrong就必然等于0,而不会等于INITIAL_STRONG_VALUE值,因此,这里就不需要 delete目标对象了(impl->mBase),因为前面的RefBase::decStrong函数会负责delete这个对象。这里唯一需 要做的就是把weakref_impl对象delete掉,但是,为什么要在这里delete这个weakref_impl对象呢?这里的weakref_impl对象是在RefBase的构造函数里面new出来的,理论上说应该在在RefBase的析构函数里delete掉这个weakref_impl对象的。在RefBase的析构函数里面,的确是会做这件事情:
- RefBase::~RefBase()
- {
- // LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
- if (mRefs->mWeak == 0) {
- // LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
- delete mRefs;
- }
- }
但是不要忘记,在这个场景下,目标对象是前面的RefBase::decStrong函数delete掉的,这时候目标对象就会被析构,但是它的弱引用计数值尚未执行减1操作,因此,这里的mRefs->mWeak == 0条件就不成立,于是就不会delete这个weakref_impl对象,因此,就延迟到执行这里decWeak函数时再执行。
如果是后一种情景,这里的impl->mStrong值就等于INITIAL_STRONG_VALUE 了,这时候由于没有地方会负责delete目标对象,因此,就需要把目标对象(imp->mBase)delete掉了,否则就会造成内存泄漏。在 delete这个目标对象的时候,就会执行RefBase类的析构函数,这时候目标对象的弱引用计数等于0,于是,就会把weakref_impl对象也一起delete掉了。
回到外层的if语句中,如果目标对象的生命周期是受弱引用计数控制的,就执行下面语句:
- impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
- delete impl->mBase;
- }
分析到这里,有必要小结一下:
A. 如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;
B. 如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象;
C. 如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁来delete掉。
到了这里,强指针就分析完成了,最后来分析弱指针。
4. 弱指针
弱指针所使用的引用计数类与强指针一样,都是RefBase类,因此,这里就不再重复介绍了,我们直接来弱指针的实现,它定义在frameworks/base/include/utils/RefBase.h文件中:
- template <typename T>
- class wp
- {
- public:
- typedef typename RefBase::weakref_type weakref_type;
- inline wp() : m_ptr(0) { }
- wp(T* other);
- wp(const wp<T>& other);
- wp(const sp<T>& other);
- template<typename U> wp(U* other);
- template<typename U> wp(const sp<U>& other);
- template<typename U> wp(const wp<U>& other);
- ~wp();
- // Assignment
- wp& operator = (T* other);
- wp& operator = (const wp<T>& other);
- wp& operator = (const sp<T>& other);
- template<typename U> wp& operator = (U* other);
- template<typename U> wp& operator = (const wp<U>& other);
- template<typename U> wp& operator = (const sp<U>& other);
- void set_object_and_refs(T* other, weakref_type* refs);
- // promotion to sp
- sp<T> 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<T>& o) const {
- return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
- }
- template<typename U>
- inline bool operator == (const wp<U>& o) const {
- return m_ptr == o.m_ptr;
- }
- inline bool operator > (const wp<T>& o) const {
- return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
- }
- template<typename U>
- inline bool operator > (const wp<U>& o) const {
- return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
- }
- inline bool operator < (const wp<T>& o) const {
- return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
- }
- template<typename U>
- inline bool operator < (const wp<U>& o) const {
- return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
- }
- inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
- template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
- inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
- template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
- inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
- template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
- private:
- template<typename Y> friend class sp;
- template<typename Y> friend class wp;
- T* m_ptr;
- weakref_type* m_refs;
- };
先来看构造函数:
- template<typename T>
- wp<T>::wp(T* other)
- : m_ptr(other)
- {
- if (other) m_refs = other->createWeak(this);
- }
- RefBase::weakref_type* RefBase::createWeak(const void* id) const
- {
- mRefs->incWeak(id);
- return mRefs;
- }
再来看析构函数:
- template<typename T>
- wp<T>::~wp()
- {
- if (m_ptr) m_refs->decWeak(this);
- }
分析到这里,弱指针还没介绍完,它最重要的特性我们还没有分析到。前面我们说过,弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密 就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指 针了:
- template<typename T>
- sp<T> wp<T>::promote() const
- {
- return sp<T>(m_ptr, m_refs);
- }
我们再来看看这个强指针的构造过程:
- template<typename T>
- sp<T>::sp(T* p, weakref_type* refs)
- : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
- {
- }
- 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);
- // 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->addWeakRef(id);
- impl->addStrongRef(id);
- #if PRINT_REFS
- LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
- #endif
- if (curCount == INITIAL_STRONG_VALUE) {
- android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
- impl->mBase->onFirstRef();
- }
- return true;
- }
这个函数的作用是试图增加目标对象的强引用计数,但是有可能会失败,失败的原因可能是因为目标对象已经被delete掉了,或者是其它的原因,下面会分 析到。前面我们在讨论强指针的时候说到,增加目标对象的强引用计数的同时,也会增加目标对象的弱引用计数,因此,函数在开始的地方首先就是调用 incWeak函数来先增加目标对象的引用计数,如果后面试图增加目标对象的强引用计数失败时,会调用decWeak函数来回滚前面的incWeak操 作。
这里试图增加目标对象的强引用计数时,分两种情况讨论,一种情况是此时目标对象正在被其它强指针引用,即它的强引用计数大于0,并且不等于 INITIAL_STRONG_VALUE,另一种情况是此时目标对象没有被任何强指针引用,即它的强引用计数小于等于0,或者等于 INITIAL_STRONG_VALUE。
第一种情况比较简单,因为这时候说明目标对象一定存在,因此,是可以将这个弱指针提升为强指针的,在这种情况下,只要简单地增加目标对象的强引用计数值就行了:
- while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
- if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
- break;
- }
- curCount = impl->mStrong;
- }
- int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
- volatile int32_t* addr);
- #define android_atomic_cmpxchg android_atomic_release_cas
第二种情况比较复杂一点,因为这时候目标对象可能还存在,也可能不存了,这要根据实际情况来判断。如果此时目标对象的强引用计数值等于 INITIAL_STRONG_VALUE,说明此目标对象还从未被强指针引用过,这时候弱指针能够被提升为强指针的条件就为:
- allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
- || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
即如果目标对象的生命周期只受到强引用计数控制或者在目标对象的具体实现中总是允许这种情况发生。怎么理解呢?如果目标对象的生命周期只受强引用计数控 制(它的标志位mFlags为0),而这时目标对象又还未被强指针引用过,它自然就不会被delete掉,因此,这时候可以判断出目标对象是存在的;如果 目标对象的生命周期受弱引用计数控制(OBJECT_LIFETIME_WEAK),这时候由于目标对象正在被弱指针引用,因此,弱引用计数一定不为0, 目标对象一定存在;如果目标对象的生命周期不受引用计数控制(BJECT_LIFETIME_FOREVER),这时候目标对象也是下在被弱指针引用,因 此,目标对象的所有者必须保证这个目标对象还没有被delete掉,否则就会出问题了。在后面两种场景下,因为目标对象的生命周期都是不受强引用计数控制 的,而现在又要把弱指针提升为强指针,就需要进一步调用目标对象的onIncStrongAttempted来看看是否允许这种情况发生,这又该怎么理解 呢?可以这样理解,目标对象的设计者可能本身就不希望这个对象被强指针引用,只能通过弱指针来引用它,因此,这里它就可以重载其父类的 onIncStrongAttempted函数,然后返回false,这样就可以阻止弱指针都被提升为强指针。在RefBase类中,其成员函数 onIncStrongAttempted默认是返回true的:
- bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
- {
- return (flags&FIRST_INC_STRONG) ? true : false;
- }
如果此时目标对象的强引用计数值小于等于0,那就说明该对象之前一定被强指针引用过,这时候就必须保证目标对象是被弱引用计数控制的 (BJECT_LIFETIME_WEAK),否则的话,目标对象就已经被delete了。同样,这里也要调用一下目标对象的 onIncStrongAttempted成员函数,来询问一下目标对象在强引用计数值小于等于0的时候,是否允计将弱指针提升为强指针。下面这个代码段 就是执行上面所说的逻辑:
- 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);
函数attemptIncStrong的主体逻辑大概就是这样了,比较复杂,读者要细细体会一下。函数的最后,如果此弱指针是允计提升为强指针的,并且此目标对象是第一次被强指针引用,还需要调整一下目标对象的强引用计数值:
- if (curCount == INITIAL_STRONG_VALUE) {
- android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
- impl->mBase->onFirstRef();
- }
分析到这里,弱指针就介绍完了。强指针和弱指针的关系比较密切,同时它们也比较复杂,下面我们再举一个例子来说明强指针和弱指针的用法,同时也验证一下它们的实现原理。
5. 强指针和弱指针的用法
参考一文,我们在external目录下建立一个C++工程目录weightpointer,它里面有两个文件,一个weightpointer.cpp文件,另外一个是Android.mk文件。
源文件weightpointer.cpp的内容如下:
- #include <stdio.h>
- #include <utils/RefBase.h>
- #define INITIAL_STRONG_VALUE (1<<28)
- using namespace android;
- class WeightClass : public RefBase
- {
- public:
- void printRefCount()
- {
- int32_t strong = getStrongCount();
- weakref_type* ref = getWeakRefs();
- printf("-----------------------\n");
- printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong));
- printf("Weak Ref Count: %d.\n", ref->getWeakCount());
- printf("-----------------------\n");
- }
- };
- class StrongClass : public WeightClass
- {
- public:
- StrongClass()
- {
- printf("Construct StrongClass Object.\n");
- }
- virtual ~StrongClass()
- {
- printf("Destory StrongClass Object.\n");
- }
- };
- class WeakClass : public WeightClass
- {
- public:
- WeakClass()
- {
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- printf("Construct WeakClass Object.\n");
- }
- virtual ~WeakClass()
- {
- printf("Destory WeakClass Object.\n");
- }
- };
- class ForeverClass : public WeightClass
- {
- public:
- ForeverClass()
- {
- extendObjectLifetime(OBJECT_LIFETIME_FOREVER);
- printf("Construct ForeverClass Object.\n");
- }
- virtual ~ForeverClass()
- {
- printf("Destory ForeverClass Object.\n");
- }
- };
- void TestStrongClass(StrongClass* pStrongClass)
- {
- wp<StrongClass> wpOut = pStrongClass;
- pStrongClass->printRefCount();
- {
- sp<StrongClass> spInner = pStrongClass;
- pStrongClass->printRefCount();
- }
- sp<StrongClass> spOut = wpOut.promote();
- printf("spOut: %p.\n", spOut.get());
- }
- void TestWeakClass(WeakClass* pWeakClass)
- {
- wp<WeakClass> wpOut = pWeakClass;
- pWeakClass->printRefCount();
- {
- sp<WeakClass> spInner = pWeakClass;
- pWeakClass->printRefCount();
- }
- pWeakClass->printRefCount();
- sp<WeakClass> spOut = wpOut.promote();
- printf("spOut: %p.\n", spOut.get());
- }
- void TestForeverClass(ForeverClass* pForeverClass)
- {
- wp<ForeverClass> wpOut = pForeverClass;
- pForeverClass->printRefCount();
- {
- sp<ForeverClass> spInner = pForeverClass;
- pForeverClass->printRefCount();
- }
- }
- int main(int argc, char** argv)
- {
- printf("Test Strong Class: \n");
- StrongClass* pStrongClass = new StrongClass();
- TestStrongClass(pStrongClass);
- printf("\nTest Weak Class: \n");
- WeakClass* pWeakClass = new WeakClass();
- TestWeakClass(pWeakClass);
- printf("\nTest Froever Class: \n");
- ForeverClass* pForeverClass = new ForeverClass();
- TestForeverClass(pForeverClass);
- pForeverClass->printRefCount();
- delete pForeverClass;
- return 0;
- }
在main函数里面,分别实例化了这三个类的对象出来,然后分别传给TestStrongClass函数、TestWeakClass函数和 TestForeverClass函数来说明智能指针的用法,我们主要是通过考察它们的强引用计数和弱引用计数来验证智能指针的实现原理。
编译脚本文件Android.mk的内容如下:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE_TAGS := optional
- LOCAL_MODULE := weightpointer
- LOCAL_SRC_FILES := weightpointer.cpp
- LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils
- include $(BUILD_EXECUTABLE)
- USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer
- USER-NAME@MACHINE-NAME:~/Android$ make snod
- USER-NAME@MACHINE-NAME:~/Android$ adb shell
- root@android:/ # cd system/bin/
- root@android:/system/bin # ./weightpointer
- Test Strong Class:
- Construct StrongClass Object.
- -----------------------
- Strong Ref Count: 0.
- Weak Ref Count: 1.
- -----------------------
- -----------------------
- Strong Ref Count: 1.
- Weak Ref Count: 2.
- -----------------------
- Destory StrongClass Object.
- spOut: 0x0.
在TestStrongClass函数里面,首先定义一个弱批针wpOut指向从main函数传进来的StrongClass对象,这时候我们可以看到 StrongClass对象的强引用计数和弱引用计数值分别为0和1;接着在一个大括号里面定义一个强指针spInner指向这个StrongClass 对象,这时候我们可以看到StrongClass对象的强引用计数和弱引用计数值分别为1和2;当程序跳出了大括号之后,强指针spInner就被析构 了,从上面的分析我们知道,强指针spInner析构时,会减少目标对象的强引用计数值,因为前面得到的强引用计数值为1,这里减1后,就变为0了,又由 于这个StrongClass对象的生命周期只受强引用计数控制,因此,这个StrongClass对象就被delete了,这一点可以从后面的输出 (“Destory StrongClass Object.”)以及试图把弱指针wpOut提升为强指针时得到的对象指针为0x0得到验证。
执行TestWeakClass函数的输出为:
- Test Weak Class:
- Construct WeakClass Object.
- -----------------------
- Strong Ref Count: 0.
- Weak Ref Count: 1.
- -----------------------
- -----------------------
- Strong Ref Count: 1.
- Weak Ref Count: 2.
- -----------------------
- -----------------------
- Strong Ref Count: 0.
- Weak Ref Count: 1.
- -----------------------
- spOut: 0xa528.
- Destory WeakClass Object.
TestWeakClass函数和TestStrongClass函数的执行过程基本一样,所不同的是当程序跳出大括号之后,虽然这个 WeakClass对象的强引用计数值已经为0,但是由于它的生命周期同时受强引用计数和弱引用计数控制,而这时它的弱引用计数值大于0,因此,这个 WeakClass对象不会被delete掉,这一点可以从后面试图把弱批针wpOut提升为强指针时得到的对象指针不为0得到验证。
执行TestForeverClass函数的输出来:
- Test Froever Class:
- Construct ForeverClass Object.
- -----------------------
- Strong Ref Count: 0.
- Weak Ref Count: 1.
- -----------------------
- -----------------------
- Strong Ref Count: 1.
- Weak Ref Count: 2.
- -----------------------
- -----------------------
- Strong Ref Count: 0.
- Weak Ref Count: 0.
- -----------------------
- Destory ForeverClass Object.
这样,从TestStrongClass、TestWeakClass和TestForeverClass这三个函数的输出就可以验证了我们上面对Android系统的强指针和弱指针的实现原理的分析。
至此,Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理就分析完成了,它实现得很小巧但是很精致,希望读者可以通过实际操作细细体会一下。
老罗的新浪微博:,欢迎关注!
- 上一篇:
- 下一篇:
- 顶
- 29
- 踩
- 0
- 27楼 2013-12-19 20:29发表
- 没怎么看懂,mark下来,有时间慢慢研究吧。
- 26楼 2013-11-26 16:47发表
- 只能说LZ太强大了,太牛逼了!!
- 25楼 2013-11-26 15:32发表
- Hi, LZ打扰下。有个问题请教下。 文中这样写道: 但 是前面为什么又调用了一次addWeakRef函数呢?前面不是已经调用过了吗?在Release版本中,因为weakref_impl类的 addWeakRef函数是空实现,这里再调用一次没有什么害处,但是如果在Debug版本,岂不是冗余了吗?搞不清,有人问过负责开发Android系 统Binder通信机制模块的作者Dianne Hackborn这个问题,他是这样回答的: ==========》 我看了下源码,那个addStrongRef 和addWeakRef 都会去调到addRef,里面不是做加一的动作, 而是将对象(ID)添加到链表上, 所以我个人觉得实际上 没有“加一”两次啊。 不知道我是否理解错了,期待大神LZ的回复。
- 24楼 2013-11-20 13:47发表
- 从楼主的文章中学到好多,刚看了这篇文章,有一点有疑议: 你在小结B提到如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会自动delete掉这个对象。 我认为应该是都为0或者弱引用计数为0强引用计数为INITIAL_STRONG_VALUE的时候delete,第二种情况是从来没有强引用指针指向引用对象。 谢谢楼主
- 23楼 2013-11-04 11:11发表
- 非常精彩的分析,使得我之前看源码的时候的一些疑问解决了不少。
- 22楼 2013-07-29 10:56发表
- 看看往前翻翻,差不多看明白了!
- 21楼 2013-07-17 17:44发表
- 看了一遍还是没看明白!
- 20楼 2013-05-04 22:42发表
- 其中关于weakref_impl和weakref_type的设计思想,表面上是weakref_impl是继承自weakref_type,但在实际的代码当中,weakref_type却反向依赖weakref_impl来了,这导致整个分离变得没有意义了。
- Re: 2013-05-05 23:56发表
- 回复L173864930:weakref_type的实现的确是有些问题,它默认只有weakref_impl会继承它,因此,它有时候会将自己强转为weakref_impl处理。
- 19楼 2012-10-25 19:08发表
- 楼主,sp 引用OBJECT_LIFETIME_FOREVER类型的对象,sp析构时,会释放OBJECT_LIFETIME_FOREVER类型的对象的对象啊 if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { delete this; }
- Re: 2012-10-25 19:36发表
- 回复gaozh1986:OBJECT_LIFETIME_FOREVER的值等于3,OBJECT_LIFETIME_WEAK的值等于1,所以这个if语句为false,不会delete掉对象。
- 18楼 2012-08-18 23:10发表
- 罗兄,下面这段话让人有点走火入魔: 这 里的成员变量mRefs的类型为weakref_impl指针,weakref_impl类的incWeak函数我们在前面已经看过了,它的作用就是增加 对象的弱引用计数。函数最后返回mRefs,于是,弱指针对象的成员变量m_refs就指向目标对象的weakref_impl对象了。 这 个“目标对象”,根据上下文的理解,读者一般会认为是泛型T的对象。但是你又说是weakref_impl对象。期待你的书面世,我认为你不管是文风还是 技术解析,都是典范,现在CSDN上写android文章的一些所谓的大牛,写技术文章跟记流水帐一样,很不好。我希望你在你的新书当中加入一章,写写你 的研究方法,学习方法,授人以渔。
- Re: 2012-08-19 00:03发表
- 回复zzb_boy:目标对象T是从RefBase类继承下来的,而RefBase类有一个成员变量mRefs,指向一个weakref_impl对象。 弱指针类wp也有一个成员变量m_refs,从wp类的构造函数可以知道,它指向的就是目标对象T的成员变量mRefs所指向的那个weakref_impl对象。 不知道你是不是指“目标对象的weakref_impl对象”这句话?如果是的话,可能是表述的不是太准确,不过上面的理解是没有问题的。 至于你提到的学习方法嘛,貌似大家都比较有兴趣,以后我考虑可以整理一下,加再个现场操作的视频,可能就会更好一些。不过由于新书已经定型了,书里就不会包含有这些东西了。大家可以关注一下我的博客,这里会持续地有新的东西放出来。 多谢你的建议。
- 17楼 2012-07-18 12:44发表
- 你好,博主。 看完这章节后有点疑惑,请教一下: 在main_mediaserver.cpp的main函数中的 为什么第一行代码要写成 sp<ProcessState> proc(ProcessState::self()); 而不直接写 ProcessState::self()? 是否是因为ProcessState::self这个函数中虽然gProcess是个智能指针,但是 if (gProcess == NULL) gProcess = new ProcessState; 这行代码并没有起到对引用数加1的功能,因此在main中需要用proc这个智能指针起到这样一个作用?那ProcessState这个对象又是在什么时候销毁的呢? 另外智能指针在初始化的时候指向一个对象,然后又在其他地方把这个智能指针指向了另一个对象,那是否先前那个对象永远不能被销毁了(因为初始的时候引用数加1了,但智能指针指向另一个对象时,先前那个对象却没有被-1)? 还有一个情况是,智能指针和普通指针混合着用,比如和一个对象既有智能指针指向它又有普通指针指向它,那是否通过普通指针进行操作的时候有可能这个已经被销毁了,而引起问题?
- Re: 2012-07-18 21:27发表
- 回复huangzhenyu1983:1. 直接用ProcessState::self()也是可以的,不过如果需要多次引用ProcessState::self()的话,用一个独立的变量proc来指向它会更方便一些,至少可以少敲一些字母。这纯粹是使用习惯问题。 2. 当把一个裸指针赋值给一个智能指针的时候,这个裸指针所指向的对象的引用计数就会被增加1,这是智能指针的属性,否则就不能称为“智能”了。 3. 智能指针是一个对象,当它被析构的时候,就会自动减少它所引用的对象的引用计数。当被引用的对象的引用计数等于0的时候,就会被销毁。 4. 当一个智能指针从一个对象指向另一个对象的时候,前一个对象的引用计数会自动被减少1。这也是智能指针的属笥,否则也不能称为“智能”了。 5. 如果一个对象既被智能指针引用,又被裸指针引用,那么就需要由开发人员来保证这个对象的生命周期。根本就不应该这样使用。
- 16楼 2012-07-07 12:20发表
- 受教了,非常不错,非常感谢楼主的分享!
- 15楼 2012-05-09 22:55发表
- 刚看完第三段,有个小小的问题,照楼主所说的,假设A引用了B,B又引用了A,那么谁是父对象,谁是子对象呢?
- Re: 2012-05-10 00:26发表
- 回复lulinlin2010:取决于A和B的业务关系,不同的业务可能不一样
- 14楼 2012-03-29 14:38发表
- 搞得很复杂!
- 13楼 2011-11-02 18:01发表
- 先谢谢LZ的详细分析。对于sp、wp相互的关系,我基本明白了,但对于它们的用处还是不大明白。比如什么时候用sp,什么时候用wp,我还是不清楚。如果我全部用sp,会有什么问题?还请LZ能解释一下。
- Re: 2011-11-02 22:09发表
- 回 复fdasf:文章中的第三段提到它们的用处了。这里再举一个例子,例如,你有一个ObjectMgr类,专门负责管理系统中的对象Obj的生命周期,创 建和销毁等,而类A通过从ObjectMgr中获得对象Obj的引用来使用它们,但是类A无权干涉对象Obj的生命周期。这时候,如果类A在内部保存了对 象Obj的引用,而此时ObjectMgr由于某些原因,需要销毁对象Obj,那么这个对象在类A中的引用就失效了。如果类A还是继续通过内部的引用而使 用对象Obj,那肯定就会出问题,但是如果类A在内部保存的是对象Obj的弱引用,那么就不会有问题,因为当类A要使用Obj的时候,必须要把它内部的弱 引用提升为强引用之后才能使用,这时候对象Obj已经不存在,提升为强引用就肯定会失败。
- Re: 2011-11-03 16:12发表
- 回复Luoshengyang:你说的这个意思我明白,但还是不清楚两者使用的时机。就针对你说的这个例子,那么我是不是可以认为,所有的地方都使用wp比较安全?如果不是这样,那么什么时候我们可以直接使用sp?
- Re: 2011-11-03 21:33发表
- 回 复fdasf:如果都用wp,那么和都用sp没有区别,关键是这样做的话,那么只要是获得了这个对象的引用的地方,都有权干涉对象的生命周期了。这个使用 场景的前提是有一个专门的地方来负责对象的生命周期,其它地方只能在这个对象存在的时候就可以用,不存在的时候就不可以使用。
- 12楼 2011-10-27 16:44发表
- 看得脑袋晕晕的
- 11楼 2011-10-07 20:53发表
- 文章分析的比较透彻,辛苦了!
- 10楼 2011-09-29 12:35发表
- 技术神贴~ 感谢分享。
- 9楼 2011-09-27 17:59发表
- 感谢楼主分享,看了下,还是有好多不懂的。下去细细研究下!
- 8楼 2011-09-27 09:39发表
- 谢谢分享。不过在我们跨平台开发中还是倾向于用boost的智能指针。
- Re: 2011-09-27 10:11发表
- 回复xiguayipian:跨平台的确是个问题,用第三方的库来屏蔽平台特性是个好方法,可能Google也正是考虑到Android系统是个开放的平台,面向的是众多的移动设备厂商,所以才决定用Java语言来开发Android的APP的吧。
- Re: 2011-09-27 15:37发表
- 回复Luoshengyang:老罗,看了你的文章,写得确实很好,从Android的内核编译开始,到与硬件的连接……我的QQ:1514008185,您方便的话加我一下好吗?我有些问题想向您请教!
- 7楼 2011-09-26 12:49发表
- 师弟文章很好
- Re: 2011-09-26 13:12发表
- 回复PinkFloyd:柯师兄,好啊:)
- Re: 2013-03-11 12:09发表
- 回复Luoshengyang:莫非是柯元旦? 哈哈,我这儿有一本书叫<Android内核剖析>,是柯元旦写的
- 6楼 2011-09-25 16:53发表
- 非常精彩。 感觉android中的sp、wp都可以弱化,sp可以所化为wp,而wp可以进一步弱化为普通指针,就是由于这个弱化功能,导致了巨复杂的实现,楼主能不能说明一下弱化到底有什么作用?? 关于弱指针在chrome中也有非常精彩的实现,可以参考http://www.oschina.net/code/explore/chromium.r67069/o3d/core/cross/weak_ptr.h
- Re: 2011-09-25 16:59发表
- 回复wormsun:文章中的第三段提到了: ......弱引用计数主要是用于垃圾收集(Garbage Collection)系统的,因为简单的引用计数技术不能处理系统中对象间循环引用的情况...... 其实在Java的垃圾收集(Garbage Collection)系统里面,对象的引用计数除了强引用计数和弱引用计数,还有其它类型的计数存在,比这个复杂多了。
- Re: 2011-09-25 22:01发表
- 回复Luoshengyang:多谢回复。
- 5楼 2011-09-25 09:59发表
- 受益匪浅,楼主辛苦了
- 4楼 2011-09-23 19:43发表
- 分析得不错,顶个
- 3楼 2011-09-23 17:07发表
- 越研究就越佩服Google那帮搞软件的。简直就是禽兽啊....
- 2楼 2011-09-23 14:12发表
- 非常不错!楼主辛苦了
- 1楼 2011-09-23 13:28发表
- 非常感谢,受益匪浅,再接再厉,哈哈~