- 为了能更加了解整个 Android 系统的运作,我买了老罗出版的,源码分析的书,打算在业务比较空闲的时间里慢慢学习……
- 由于在源码中经常能看到智能指针的应用,于是趁着这两天没有项目,我就把智能指针的这一章啃了一遍。
NOTE
- 参考源码版本:Android 7.1.2。
- 以下代码追踪思路均参考《Android 系统源代码情景分析(修订版)》。
为何用智能指针
- Android 系统源码中,含有大量的 c++ 代码,既然用到了 c++ ,就无法避免使用指针。
- c++ 指针若使用不当,轻则内存泄露,重则导致难以发现的逻辑错误,甚至系统崩溃。
- 为了尽可能避免错误地使用 c++ 指针,Android 系统为我们提供了 c++ 智能指针。
智能指针背景
- 我们通常通过引用计数技术来维护对象的生命周期。
- 人为手动维护计数风险很大,必须采用一种自动的引用计数维护技术。
- 智能指针:
- 它是一个对象,而非指针。但它引用了一个实际使用的对象。
- 通过在构造函数中加入引用计数来实现自动计数维护。
- 这样的简单计数无法解决相互引用的对象释放问题。
- 为了解决相互引用而引发的问题,前人提出了 “强引用” 与 “弱引用” 的概念。
A
与B
的例子:
- 条件:
A
强引用B
,B
弱引用A
。 A
的生命周期不受B
的影响,故A
可以安全地释放空间。- 在释放
A
时,同时也会释放它对B
的强引用计数,此时B
也就可以安全地释放空间了。 - 对象的生命周期不受弱引用计数控制:
- 情景: 当
B
想要使用A
,此时A
已经释放。 B
若想使用对象A
,则需要先将弱引用升级为强引用。- 由于
A
已经释放,所以这个弱引用无法升级。 - 弱引用无法升级,则可判断
B
已经无法再使用A
。
- 情景: 当
- 条件:
Android 智能指针分类
- 轻量级指针:Light Pointer
- 强指针:Strong Pointer
- 弱指针:Weak Pointer
轻量级指针
1. 轻量级指针实现原理
1.1 RefBase.h
- 位置:
system/core/include/utils/RefBase.h
LightRefBase
的实现:
- 模板类:
T
表示实际类型,它必须继承LightRefBase
(前提是它只需要用到轻量指针)。 - 只有一个成员变量
mCount
用于描述引用计数值。 - 提供
incStrong
与decStrong
来增加、减少引用计数。 - 注意一些新增的东西:
__attribute__((unused))
:该函数或变量可能不使用,可避免编译器警告。atomic
:保证关于它的操作是原子性的- 友元类
ReferenceMover
static
函数renameRef()
:空函数static
函数renameRefId()
:空函数
- 模板类:
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;
protected:
inline ~LightRefBase() { }
private:
friend class ReferenceMover;
inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
inline static void renameRefId(T* ref,
const void* old_id, const void* new_id) { }
private:
mutable std::atomic<int32_t> mCount;
};
1.2 StrongPointer.h
- 轻量级指针实现类
sp
:
- 它同时也是强指针的实现类。
- 模板类:
T
必须继承LightRefBase
。 - 与轻量级指针相关的部分:
m_ptr
:指向了引用的实际对象。- 构造函数:增加计数。
- 析构函数:减少计数。
template<typename T>
class sp {
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
sp(sp<T>&& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
template<typename U> sp(sp<U>&& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
sp& operator = (sp<T>&& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (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;
void set_pointer(T* ptr);
T* m_ptr;
};
- 构造函数与析构函数:
- 由于
m_ptr
指向的对象继承了LightRefBase
,所以这里实际上是通过调用LightRefBase
类的incStrong
与decStrong
来改变计数的。
- 由于
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(sp<T>&& other)
: m_ptr(other.m_ptr) {
other.m_ptr = nullptr;
}
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
2. 轻量级指针的使用
- 轻量级指针比较简单,与它相关的就只有这一点内容。
- 为了巩固对轻量级指针的理解,我照着老罗给的例子写了实践的代码,在模拟器上跑了下面这个小程序。
- 在源码目录下的
external/
中创建一个文件夹lightpointer
。 - 相关文件:
external/lightpointer/Android.mk
external/lightpointer/lightpointer.cpp
lightpointer.cpp
实现:
#include <stdio.h>
#include <utils/RefBase.h>
using namespace android;
class LightClass : public LightRefBase<LightClass>
{
public :
LightClass()
{
printf("Construct LightClass Object.\n");
}
virtual ~LightClass()
{
printf("Destroy LightClass Object.\n");
}
};
int main(int argc, char** argv)
{
LightClass* pLightClass = new LightClass();
sp<LightClass> lpOut;
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)
- 单独编译指令:
mmm ./external/lightpointer/
make snod
编译成功后,用
adb shell
进入system/bin
,运行lightpointer
:
- 结果如下。
Construct LightClass Object.
Light Ref count : 1.
Light Ref count : 2.
Light Ref count : 1.
Destroy LightClass Object.- 结果如下。
分析输出:
- 开始时,我们创建了一个
LightClass
实例pLightClass
。 - 注意,这个
LightClass
继承了LightRefBase
。 - 创建一个轻量级指针
lpOut
指向pLightClass
,此时计数器+1
,计数值为1
。 - 再次创建轻量级指针
lpInner
指向lpOut
,此时pLightClass
的计数+1
,计数值为2
。 - 注意到
lpInner
的生命周期在第二次输出计数值后就结束了,此时计数-1
,计数值为1
。
- 开始时,我们创建了一个