《深入理解Android卷 I》- 第五章 - 理解常见类 - 读书笔记

1 RefBase, sp, wp

在Android中,RefBase结合sp和wp,实现了一套通过引用计数的方法来控制对象生命周期的机制。

1.1 初识影子对象

refBase是实现引用计数的基类,提供引用计数的方法。简单示例:

class A: public RefBase {
  //..
}
int main() {
  A* pA = new A;
  {
    //sp,wp对象是在{}中创建的,下面的代码先创建sp,然后创建wp
    sp<A>spA(A);
    wp<A>wpA(spA);
    //大括号结束前,先析构wp,再析构sp
  }
}

1.1.1 RefBase和它的影子

示例代码中 class A继承自RefBase,使用的是RefBase的构造函数

system/core/libutils/RefBase.cpp

RefBase::RefBase()
    : mRefs(new weakref_impl(this)){
    }

mRefsRefBase的内部类weakref_type的子类weakref_impl的实例,保存在RefBase中的一个字段。

class RefBase::weakref_impl : public RefBase::weakref_type {
public:
    std::atomic<int32_t>    mStrong;
    std::atomic<int32_t>    mWeak;
    RefBase* const          mBase;
    std::atomic<int32_t>    mFlags;
  
    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)
    {
    }
}

通过上面代码可知,在创建A对象的同时也创建了一个weakref_type对象,称为影子。

影子中的两个字段就关系对象的生死。

1.1.2 sp

system/core/include/utils/StrongPointer.h

继续查看实例代码中构造一个sp引用sp<A> spA(A)

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this);
}

其中T必须继承自RefBase,构建sp引用后代码就执行了inctrong(this),该方法是RefBase提供

system/core/libutils/RefBase.cpp

void RefBase::incStrong(const void* id) const {
  //mRefs是RefBase中的字段,在RefBase构造函数执行时赋值  
  weakref_impl* const refs = mRefs;
  //先增加弱引用计数
  refs->incWeak(id);
  //空实现,无视
  refs->addStrongRef(id);
  //原子操作,强引用增加1
  const int32_t c = refs->mStrong.fetch_add(1,std::memory_order_relaxed);
#if PRINT_REFS
  ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
  //判断是否为初识值
  if (c != INITIAL_STRONG_VALUE)  {
      return;
  }
 //是第一引用就会执行下面的代码
  //设置初识值
  int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
            std::memory_order_relaxed);
  // A decStrong() must still happen after us.
  ALOG_ASSERT(old > INITIAL_STRONG_VALUE, "0x%x too small", old);
  /*如果是第一次引用,则调用onFirstRef()
  这个函数很重要,派生类可以重载这个函数,完成一些初始化工作。*/
  refs->mBase->onFirstRef();
}

incWeak(id)函数

void RefBase::weakref_type::incWeak(const void* id) {
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    //空实现,无视
    impl->addWeakRef(id);
    //原子操作,弱引用增加1
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed);
}

sp构造完成后RefBaseweakref_impl实例的强弱引用都增加了1.

wp构造完成又是什么样的?

system/core/include/utils/RefBase.h

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other) //m_ptr就是继承RefBase的实际对象
{
    //调用pA的createWeak,并且保存返回值到成员变量m_refs中
    if (other) m_refs = other->createWeak(this);
}
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{   
    //mRefs就是那个new出来的weakref_impl实例
    //增加弱引用加1
    mRefs->incWeak(id);
    return mRefs;
}

回到最初的示例代码,在构造完wp后,A对象的影子对象mRefs中的mWeak增加了2,mStrong只增加了1。

wp中有两个成员变量,一个保存实际对象,另一个保存影子对象。sp只有一个成员变量用来保存实际对象,但这个实际对象内部已包含了对应的影子对象。

1.1.3 wp,sp析构

还是最初的回到实例代码里,我们是在代码块中创建的sp<A> spAwp<A> wpA两个对象,更具代码的执行,除了代码块,两个对象的析构函数就会被调用。

system/core/include/utils/RefBase.h

wp<T>::~wp()
{   
    //调用影子对象的decWeak,由影子对象的基类实现
    if (m_ptr) m_refs->decWeak(this);
}

system/core/libutils/RefBase.cpp

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    //空实现,无视
    impl->removeWeakRef(id);
    //原子操作,计数减一
    const int32_t c = impl->mWeak.fetch_sub(1,std::memory_order_release);
   
    if (c != 1) return;
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    //如果c为1,则弱引用计数为0,这说明没用弱引用指向实际对象,需要考虑是否释放内存
    // OBJECT_LIFETIME_XXX和生命周期有关系
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlives the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Decrementing a weak count to zero when object never had a strong
            // reference.  We assume it acquired a weak reference early, e.g.
            // in the constructor, and will eventually be properly destroyed,
            // usually via incrementing and decrementing the strong count.
            // Thus we no longer do anything here.  We log this case, since it
            // seems to be extremely rare, and should not normally occur. We
            // used to deallocate mBase here, so this may now indicate a leak.
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

继续示例代码,wp析构后,弱引用计数为1,但是强引用也是1,所以不能释放对象。

sp析构:

system/core/include/utils/StrongPointer.h

sp<T>::~sp() {
    if (m_ptr)
        //m_ptr就是实际对象,集成自RefBase
        m_ptr->decStrong(this);
}

system/core/libutils/RefBase.cpp

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    //无视
    refs->removeStrongRef(id);
    //减一
    const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
#if PRINT_REFS
    ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
#endif
    LOG_ALWAYS_FATAL_IF(BAD_STRONG(c), "decStrong() called on %p too many times",
            refs);
    if (c == 1) {
        std::atomic_thread_fence(std::memory_order_acquire);
        //调用onLastStrongRef,表明强引用计数减为0,对象有可能被delete
        refs->mBase->onLastStrongRef(id);
        int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            delete this;
            // The destructor does not delete refs in this case.
        }
    }
    // Note that even with only strong reference operations, the thread
    // deallocating this may not be the same as the thread deallocating refs.
    // That's OK: all accesses to this happen before its deletion here,
    // and all accesses to refs happen before its deletion in the final decWeak.
    // The destructor can safely access mRefs because either it's deleting
    // mRefs itself, or it's running entirely before the final mWeak decrement.
    //weaktype_impl对象调用减少弱引用
    refs->decWeak(id);

delete this回调用被引用的析构函数,例如示例的A类,如果强引用没有了,就把引用对象delete

RefBase::~RefBase()
{
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    // Life-time of this object is extended to WEAK, in
    // which case weakref_impl doesn't out-live the object and we
    // can free it now.
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
        // It's possible that the weak count is not 0 if the object
        // re-acquired a weak reference in its destructor
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {
        // We never acquired a strong reference on this object.
        LOG_ALWAYS_FATAL_IF(mRefs->mWeak.load() != 0,
                "RefBase: Explicit destruction with non-zero weak "
                "reference count");
        // TODO: Always report if we get here. Currently MediaMetadataRetriever
        // C++ objects are inconsistently managed and sometimes get here.
        // There may be other cases, but we believe they should all be fixed.
        delete mRefs;
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

sp执行了减少强引用之后将执行减少弱引用,如果弱引用没有了。就把weaktype_impl对象delete

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times",
            this);
    if (c != 1) return;
    atomic_thread_fence(std::memory_order_acquire);

    int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        // This is the regular lifetime case. The object is destroyed
        // when the last strong reference goes away. Since weakref_impl
        // outlives the object, it is not destroyed in the dtor, and
        // we'll have to do it here.
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Decrementing a weak count to zero when object never had a strong
            // reference.  We assume it acquired a weak reference early, e.g.
            // in the constructor, and will eventually be properly destroyed,
            // usually via incrementing and decrementing the strong count.
            // Thus we no longer do anything here.  We log this case, since it
            // seems to be extremely rare, and should not normally occur. We
            // used to deallocate mBase here, so this may now indicate a leak.
            ALOGW("RefBase: Object at %p lost last weak reference "
                    "before it had a strong reference", impl->mBase);
        } else {
           //delete影子对象
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

1.1.4 总结

RefBase中有一个隐含的影子对象,这个对象就是实际包含被引用对象和强弱引用计数;

sp构造引用后,强弱引用计数各增加1,sp析构后,强弱引用计数各减1;

wp构造引用后,弱引用增加1,wp析构后,弱引用计数减1;

完全彻底地消灭RefBase对象,包括让实际对象和影子对象灭亡,这些都是由强弱引用计数控制的,另外还要考
虑flag的取值情况。当flag为0时,可得出如下结论:

  • 强引用为0将导致实际对象被delete。
  • 弱引用为0将导致影子对象被delete。

1.2 由弱生强

代码示例:

int main(){
    A *pA =new A();
    wp<A> wpA(A);
    sp<A> spA = wpA.promote();//通过promote函数,得到一个sp。
}

1.2.1 由弱生强的方法

由示例代码可以看出,依靠函数promote()可以得到一个sp的对象

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;
}

成败全靠attemptIncStrong()

system/core/libutils/RefBase.cpp


bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id); //增加弱
    
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    int32_t curCount = impl->mStrong.load(std::memory_order_relaxed);
    //该循环在多线程操作同一个对象时会多次循环,他的目的就是让强引用加1
    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 (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
        // the strong count has changed on us, we need to re-assert our
        // situation. curCount was updated by compare_exchange_weak.
    }
    
    ....//太长了,也看不懂,也是为了保证能装换强引用
      
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}

1.2.2 结果

结果当然就是强弱增加一个返回一个强引用对象。

1.3 生命周期的管理

在构造的sp,或wp的生命周期受flag的影响。

system/core/include/utils/RefBase.h

//! Flags for extendObjectLifetime()
enum {
    OBJECT_LIFETIME_STRONG  = 0x0000,
    OBJECT_LIFETIME_WEAK    = 0x0001,
    OBJECT_LIFETIME_MASK    = 0x0001
};
  • 在flag为OBJECT_LIFETIME_WEAK时,即便sp对象的强引用计数为0,而弱引用不为0,被引用对象不会被delete,进而在减少弱引用函数中再去判断,如果弱引用也为0了,就会delete掉被引用对象。
  • 在flag为OBJECT_LIFETIME_STRONG强引用空之被引用对象的生命周期。弱引用控制影子对象的生命周期,强引用为0时,被引用对象delete。

1.3.1 轻量引用计数控制-LightRefBase

template <class T>
class LightRefBase
{
public:
    inline LightRefBase() : mCount(0) { }
    inline void incStrong(__attribute__((unused)) const void* id) const {
        mCount.fetch_add(1, std::memory_order_relaxed);
    }
    inline void decStrong(__attribute__((unused)) const void* id) const {
        if (mCount.fetch_sub(1, std::memory_order_release) == 1) {
            std::atomic_thread_fence(std::memory_order_acquire);
            delete static_cast<const T*>(this);
        }
    }
    //! DEBUGGING ONLY: Get current strong ref count.
    inline int32_t getStrongCount() const {
        return mCount.load(std::memory_order_relaxed);
    }

    typedef LightRefBase<T> basetype;
...
private:
    mutable std::atomic<int32_t> mCount;
};

这个类中仅有一个mCount用来引用计数,使用也非常简单:

class A: public LightRefBase<A> //泛型得是A

2 Thread类以及常用同步类

Thread类是Android为线程操作而做的一个封装。代码在Thread.cpp中,其中还封装了一些与线程同步相关的类

2.1 常见同步类

Android提供了两个封装好的同步类,它们是Mutex和Condition。这是重量级的同步技术,一般内核会有对应的
支持。另外,OS还提供了简单的原子操作,这些也算是同步技术的一种。

2.1.1 互斥类-Mutex

Mutex的使用必须初始化,除此之外有两个重要函数处理同步,lock(),unlock(),分别表示开始上锁,释放锁。另外,Mutex还提供了一个trylock()函数,该函数只是尝试去锁住该区域,使用者需要根据trylock的返回值判
断是否成功锁住了该区域。

Mutex类的内部还有一个AutoLock 帮助简化同步。

2.1.2 条件类-Condition

工作线程通过触发信号,唤起等待的进程。Condition的信号触发需要在lock范围中才可以

3 Looper和Handler

工作原理:

一个消息队列,其他线程可以往这个队列中添加消息。

有一个消息循环,不断的去出消息,处理消息。![looper_handler-1]

looper_handler-1.png

在Android系统中:

Looper用于封装消息循环,内部有一个消息队列

Handler它是负责消息的入队和消息的处理。

Looper中的消息队列里面存的是多个Message

每个Message中有一个Handler,用于处理Message

上一篇 《第四章 - Zygote》读书笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容