我们的“三板斧”,其实就是三个例子。相信这三板斧劈下去,你会很容易理解它们。
**例子1**
~~~
/类A从RefBase派生,RefBase是万物的始祖
class A:public RefBase
{
//A没有任何自己的功能
}
int main()
{
A* pA =new A;
{
//注意我们的sp,wp对象是在{}中创建的,下面的代码先创建sp,然后创建wp
sp<A>spA(A);
wp<A>wpA(spA);
//大括号结束前,先析构wp,再析构sp
}
}
~~~
例子够简单吧?但也需一步一步分析这斧子是怎么劈下去的。
1. RefBase和它的影子
类A从RefBase中派生。使用的是RefBase构造函数。代码如下所示:
**RefBase.cpp**
~~~
RefBase::RefBase()
:mRefs(new weakref_impl(this))//注意这句话
{
//mRefs是RefBase的成员变量,类型是weakref_impl,我们暂且叫它影子对象
//所以A有一个影子对象
}
~~~
mRefs是引用计数管理的关键类,需要进去观察。它是从RefBase的内部类weakref_type中派生出来的。
先看看它的声明:
~~~
class RefBase::weakref_impl : public RefBase::weakref_type
//从RefBase的内部类weakref_type派生
~~~
由于Android频繁使用C++内部类的方法,所以初次阅读Android代码时可能会有点不太习惯,C++的内部类和Java内部类相似,但不同的是,它需要一个显示的成员指向外部类对象,而Java内部类对象就有一个隐式的成员指向外部类对象。
说明:内部类在C++中的学名叫nested class(内嵌类)。
**RefBase.cpp::weakref_imple构造**
~~~
weakref_impl(RefBase* base)
:mStrong(INITIAL_STRONG_VALUE) //强引用计数,初始值为0x1000000
,mWeak(0) //弱引用计数,初始值为0
,mBase(base)//该影子对象所指向的实际对象
,mFlags(0)
,mStrongRefs(NULL)
,mWeakRefs(NULL)
,mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
,mRetain(false)
{
}
~~~
如你所见,new了一个A对象后,其实还new了一个weakref_impl对象,这里称它为影子对象,另外我们称A为实际对象。
这里有一个问题:影子对象有什么用?
可以仔细想一下,是不是发现影子对象成员中有两个引用计数?一个强引用,一个弱引用。如果知道引用计数和对象生死有些许关联的话,就容易想到影子对象的作用了。
按上面的分析,在构造一个实际对象的同时,还会悄悄地构造一个影子对象,在嵌入式设备的内存不是很紧俏的今天,这个影子对象的内存占用已不成问题了。
2. sp上场
程序继续运行,现在到了
~~~
sp<A> spA(A);
~~~
请看sp的构造函数,它的代码如下所示:(注意,sp是一个模板类,对此不熟悉的读者可以去翻翻书,或者干脆把所有出现的T都换成A。)
**RefBase.h::sp(T*other)**
~~~
template<typename T>
sp<T>::sp(T* other) //这里的other就是刚才创建的pA
:m_ptr(other)// sp保存了pA的指针
{
if(other) other->incStrong(this);//调用pA的incStrong
}
~~~
OK,战场转到RefBase的incStrong中。它的代码如下所示:
**RefBase.cpp**
~~~
void RefBase::incStrong(const void* id) const
{
//mRefs就是刚才RefBase构造函数中new出来的影子对象
weakref_impl*const refs = mRefs;
//操作影子对象,先增加弱引用计数
refs->addWeakRef(id);
refs->incWeak(id);
......
~~~
先来看看影子对象的这两个weak函数都干了些什么。
(1)眼见而心不烦
先来看第一个函数addWeakRef,代码如下所示:
**RefBase.cpp**
~~~
void addWeakRef(const void* /*id*/) { }
~~~
呵呵,addWeakRef啥都没做,因为这是release版走的分支。调试版的代码我们就不讨论了,它是给创造RefBase、 sp,以及wp的人调试用的。
调试版分支的代码很多,看来创造它们的人,也为不理解它们之间的暧昧关系痛苦不已。
总之,一共有这么几个不用考虑的函数,我们都已列出来了。以后再碰见它们,干脆就直接跳过的是:
~~~
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) { }
~~~
继续我们的征程。再看incWeak函数,代码如下所示:
**RefBase.cpp**
~~~
void RefBase::weakref_type::incWeak(const void*id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id); //上面说了,非调试版什么都不干
const int32_tc = android_atomic_inc(&impl->mWeak);
//原子操作,影子对象的弱引用计数加1
//千万记住影子对象的强弱引用计数的值,这是彻底理解sp和wp的关键
}
~~~
好,我们再回到incStrong,继续看代码:
**RefBase.cpp**
~~~
......
//刚才增加了弱引用计数
//再增加强引用计数
refs->addStrongRef(id);//非调试版这里什么都不干
//下面函数为原子加1操作,并返回旧值。所以c=0x1000000,而mStrong变为0x1000001
const int32_t c =android_atomic_inc(&refs->mStrong);
if (c!= INITIAL_STRONG_VALUE) {
//如果c不是初始值,则表明这个对象已经被强引用过一次了
return;
}
//下面这个是原子加操作,相当于执行refs->mStrong +(-0x1000000),最终mStrong=1
android_atomic_add(-INITIAL_STRONG_VALUE,&refs->mStrong);
/*
如果是第一次引用,则调用onFirstRef,这个函数很重要,派生类可以重载这个函数,完成一些
初始化工作。
*/
const_cast<RefBase*>(this)->onFirstRef();
}
~~~
说明:android_atomic_xxx是Android平台提供的原子操作函数,原子操作函数是多线程编程中的常见函数,读者可以学习原子操作函数知识,本章后面将对其做介绍。
(2)sp构造的影响
sp构造完后,它给这个世界带来了什么?
- 那就是RefBase中影子对象的强引用计数变为1,弱引用计数也变为1。
更准确的说法是,sp的出生导致影子对象的强引用计数加1,弱引用计数加1。
(3)wp构造的影响
继续看wp,例子中的调用方式如下:
~~~
wp<A> wpA(spA)
~~~
wp有好几个构造函数,原理都一样。来看这个最常见的:
**RefBase.h::wp(constsp<T>& other)**
~~~
template<typename T>
wp<T>::wp(const sp<T>& other)
:m_ptr(other.m_ptr) //wp的成员变量m_ptr指向实际对象
{
if(m_ptr) {
//调用pA的createWeak,并且保存返回值到成员变量m_refs中
m_refs = m_ptr->createWeak(this);
}
}
~~~
**RefBase.cpp**
~~~
RefBase::weakref_type* RefBase::createWeak(constvoid* id) const
{
//调用影子对象的incWeak,这个我们刚才讲过了,将导致影子对象的弱引用计数增加1
mRefs->incWeak(id);
returnmRefs; //返回影子对象本身
}
~~~
我们可以看到,wp化后,影子对象的弱引用计数将增加1,所以现在弱引用计数为2,而强引用计数仍为1。另外,wp中有两个成员变量,一个保存实际对象,另一个保存影子对象。sp只有一个成员变量用来保存实际对象,但这个实际对象内部已包含了对应的影子对象。
OK,wp创建完了,现在开始进入wp的析构。
(4)wp析构的影响
wp进入析构函数,这表明它快要离世了。
**RefBase.h**
~~~
template<typename T>
wp<T>::~wp()
{
if(m_ptr) m_refs->decWeak(this); //调用影子对象的decWeak,由影子对象的基类实现
}
~~~
**RefBase.cpp**
~~~
void RefBase::weakref_type::decWeak(const void*id)
{
//把基类指针转换成子类(影子对象)的类型,这种做法有些违背面向对象编程的思想
weakref_impl*const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//非调试版不做任何事情
//原子减1,返回旧值,c=2,而弱引用计数从2变为1
constint32_t c = android_atomic_dec(&impl->mWeak);
if (c !=1) return; //c=2,直接返回
//如果c为1,则弱引用计数为0,这说明没用弱引用指向实际对象,需要考虑是否释放内存
// OBJECT_LIFETIME_XXX和生命周期有关系,我们后面再说。
if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if(impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
else {
delete impl;
}
} else{
impl->mBase->onLastWeakRef(id);
if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
delete impl->mBase;
}
}
}
~~~
OK,在例1中,wp析构后,弱引用计数减1。但由于此时强引用计数和弱引用计数仍为1,所以没有对象被干掉,即没有释放实际对象和影子对象占据的内存。
(5)sp析构的影响
下面进入sp的析构。
**RefBase.h**
~~~
template<typename T>
sp<T>::~sp()
{
if(m_ptr) m_ptr->decStrong(this); //调用实际对象的decStrong。由RefBase实现
}
~~~
**RefBase.cpp**
~~~
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id);//调用影子对象的removeStrongRef,啥都不干
//注意,此时强弱引用计数都是1,下面函数调用的结果是c=1,强引用计数为0
constint32_t c = android_atomic_dec(&refs->mStrong);
if (c== 1) { //对于我们的例子, c为1
//调用onLastStrongRef,表明强引用计数减为0,对象有可能被delete
const_cast<RefBase*>(this)->onLastStrongRef(id);
//mFlags为0,所以会通过delete this把自己干掉
//注意,此时弱引用计数仍为1
if((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
delete this;
}
......
}
~~~
先看delete this的处理,它会导致A的析构函数被调用;再看A的析构函数,代码如下所示:
**例子1::~A()**
~~~
//A的析构直接导致进入RefBase的析构。
RefBase::~RefBase()
{
if(mRefs->mWeak == 0) { //弱引用计数不为0,而是1
delete mRefs;
}
}
~~~
RefBase的delete this自杀行为没有把影子对象干掉,但我们还在decStrong中,可接着从delete this往下看:
**RefBase.cpp**
~~~
....//接前面的delete this
if ((refs->mFlags&OBJECT_LIFETIME_WEAK)!= OBJECT_LIFETIME_WEAK) {
delete this;
}
//注意,实际数据对象已经被干掉了,所以mRefs也没有用了,但是decStrong刚进来
//的时候就保存mRefs到refs了,所以这里的refs指向影子对象
refs->removeWeakRef(id);
refs->decWeak(id);//调用影子对象decWeak
}
~~~
**RefBase.cpp**
~~~
void RefBase::weakref_type::decWeak(const void*id)
{
weakref_impl*const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//非调试版不做任何事情
//调用前影子对象的弱引用计数为1,强引用计数为0,调用结束后c=1,弱引用计数为0
constint32_t c = android_atomic_dec(&impl->mWeak);
if (c!= 1) return;
//这次弱引用计数终于变为0,并且mFlags为0, mStrong也为0。
if((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
if(impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
else {
delete impl; //impl就是this,把影子对象自己干掉
}
} else{
impl->mBase->onLastWeakRef(id);
if((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
delete impl->mBase;
}
}
}
~~~
好,第一板斧劈下去了!来看看它的结果是什么。
3. 第一板斧的结果
第一板斧过后,来总结一下刚才所学的知识:
- RefBase中有一个隐含的影子对象,该影子对象内部有强弱引用计数。
- sp化后,强弱引用计数各增加1,sp析构后,强弱引用计数各减1。
- wp化后,弱引用计数增加1,wp析构后,弱引用计数减1。
完全彻底地消灭RefBase对象,包括让实际对象和影子对象灭亡,这些都是由强弱引用计数控制的,另外还要考虑flag的取值情况。当flag为0时,可得出如下结论:
- 强引用为0将导致实际对象被delete。
- 弱引用为0将导致影子对象被delete。
- 前言
- 第1章 阅读前的准备工作
- 1.1 系统架构
- 1.1.1 Android系统架构
- 1.1.2 本书的架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.3 工具介绍
- 1.3.1 Source Insight介绍
- 1.3.2 Busybox的使用
- 1.4 本章小结
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 学习JNI的实例:MediaScanner
- 2.3 Java层的MediaScanner分析
- 2.3.1 加载JNI库
- 2.3.2 Java的native函数和总结
- 2.4 JNI层MediaScanner的分析
- 2.4.1 注册JNI函数
- 2.4.2 数据类型转换
- 2.4.3 JNIEnv介绍
- 2.4.4 通过JNIEnv操作jobject
- 2.4.5 jstring介绍
- 2.4.6 JNI类型签名介绍
- 2.4.7 垃圾回收
- 2.4.8 JNI中的异常处理
- 2.5 本章小结
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 属性服务
- 3.3 本章小结
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 关于zygote的总结
- 4.3 SystemServer分析
- 4.3.1 SystemServer的诞生
- 4.3.2 SystemServer的重要使命
- 4.3.3 关于 SystemServer的总结
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService发送请求
- 4.4.2 有求必应之响应请求
- 4.4.3 关于zygote分裂的总结
- 4.5 拓展思考
- 4.5.1 虚拟机heapsize的限制
- 4.5.2 开机速度优化
- 4.5.3 Watchdog分析
- 4.6 本章小结
- 第5章 深入理解常见类
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初识影子对象
- 5.2.2 第二板斧--由弱生强
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 轻量级的引用计数控制类LightRefBase
- 5.2.5 题外话-三板斧的来历
- 5.3 Thread类及常用同步类分析
- 5.3.1 一个变量引发的思考
- 5.3.2 常用同步类
- 5.4 Looper和Handler类分析
- 5.4.1 Looper类分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步关系
- 5.4.4 HandlerThread介绍
- 5.5 本章小结
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函数
- 6.2.2 独一无二的ProcessState
- 6.2.3 时空穿越魔术-defaultServiceManager
- 6.2.4 注册MediaPlayerService
- 6.2.5 秋风扫落叶-StartThread Pool和join Thread Pool分析
- 6.2.6 你彻底明白了吗
- 6.3 服务总管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服务的注册
- 6.3.3 ServiceManager存在的意义
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查询ServiceManager
- 6.4.2 子承父业
- 6.5 拓展思考
- 6.5.1 Binder和线程的关系
- 6.5.2 有人情味的讣告
- 6.5.3 匿名Service
- 6.6 学以致用
- 6.6.1 纯Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小结
- 第7章 深入理解Audio系统
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介绍
- 7.2.2 AudioTrack(Java空间)分析
- 7.2.3 AudioTrack(Native空间)分析
- 7.2.4 关于AudioTrack的总结
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的诞生
- 7.3.2 通过流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 关于AudioFlinger的总结
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的创建
- 7.4.2 重回AudioTrack
- 7.4.3 声音路由切换实例分析
- 7.4.4 关于AudioPolicy的总结
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 题外话
- 7.6 本章小结
- 第8章 深入理解Surface系统
- 8.1 概述
- 8.2 一个Activity的显示
- 8.2.1 Activity的创建
- 8.2.2 Activity的UI绘制
- 8.2.3 关于Activity的总结
- 8.3 初识Surface
- 8.3.1 和Surface有关的流程总结
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI层分析
- 8.3.4 Surface和画图
- 8.3.5 初识Surface小结
- 8.4 深入分析Surface
- 8.4.1 与Surface相关的基础知识介绍
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface对象的创建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介绍
- 8.4.7 深入分析Surface的总结
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的诞生
- 8.5.2 SF工作线程分析
- 8.5.3 Transaction分析
- 8.5.4 关于SurfaceFlinger的总结
- 8.6 拓展思考
- 8.6.1 Surface系统的CB对象分析
- 8.6.2 ViewRoot的你问我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小结
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理与机制分析
- 9.2.1 Netlink和Uevent介绍
- 9.2.2 初识Vold
- 9.2.3 NetlinkManager模块分析
- 9.2.4 VolumeManager模块分析
- 9.2.5 CommandListener模块分析
- 9.2.6 Vold实例分析
- 9.2.7 关于Vold的总结
- 9.3 Rild的原理与机制分析
- 9.3.1 初识Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 关于Rild main函数的总结
- 9.3.6 Rild实例分析
- 9.3.7 关于Rild的总结
- 9.4 拓展思考
- 9.4.1 嵌入式系统的存储知识介绍
- 9.4.2 Rild和Phone的改进探讨
- 9.5 本章小结
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模块分析
- 10.2.2 MSS模块分析
- 10.2.3 android.process.media媒体扫描工作的流程总结
- 10.3 MediaScanner分析
- 10.3.1 Java层分析
- 10.3.2 JNI层分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 关于MediaScanner的总结
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介绍
- 10.4.2 我问你答
- 10.5 本章小结