Android框架层基础3————智能指针
本文基于Android 8.0
一.智能指针概述
在查看Android Native层代码时,经常会接触到sp,wp的变量。这两个变量有什么含义呢?
在Android系统中,Native层代码基本是由c++写的,c++跟java不一样,c++没有垃圾回收机制,所以稍不注意就会导致内存泄漏。
针对上面的问题,Android提出了一套类型与Java垃圾回收机制的稚嫩和指针。采用的强指针(Strong Pointer)和弱指针(Weak Pointer)对目标进行应用,实现对象的自动回收
在了解智能指针之前,简单的了解一些智能指针牵扯的基础知识。
二.相关基础知识
1.c++作用域
标记变量的有效范围。从作用域上来看,可以将对象分为全局对象、局部对象、静态全局对象和静态局部对象。
一般来说,局部变量的有效作用域从它的定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号,也就是说,作用域由变量所在的最近一对{}括号确定。
void testScope() {
SheepbigSheep; //局部对象
{
SheepsmallSheep; // 局部对象
} //SheepsmallSheep的作用域结束
} // SheepbigSheep的作用域结束
2.对象的内存的分配,释放
在现在的操作系统中,每个进程都拥有固定大小(4G)的虚拟内存,虚拟内存是将空间按照如下方式进行分配。
在C++中类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* p=new A(),Ap=(A)malloc();
静态建立一个类对象,是由编译器为对象在栈空间中分配内存,通过直接移动栈顶指针挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。栈是由编译器自动分配释放 ,存放函数的参数值,局部变量的值,对象的引用地址等。其操作方式类似于数据结构中的栈,通常都是被调用时处于存储空间中,调用完毕立即释放。
动态建立类对象,是使用new运算符将对象建立在堆空间中,在栈中只保留了指向该对象的指针。堆中通常保存程序运行时动态创建的对象,C++堆中存放的对象需要由程序员分配释放,它存在程序运行的整个生命期,直到程序结束由OS释放。而在java中通常类的对象都分配在堆中,对象的回收由虚拟机的GC垃圾回收机制决定。
3.C++中一些基本语法
构造函数
构造函数简单而言,是为了代码的简洁,一次性为所有属性初始化,c++的类提供了这样一个函数——构造函数。它有如下特点:
- 构造函数是一种特殊的成员函数,不需要用户调用,定义对象时被自动执行
- 构造函数名字与类名相同,无返回类型
- 可以由用户自定义实现,需要设计对数据类型的进行初始化,依旧可以设置函数默认参数。
- 如果我们没有定义构造函数,系统会为我们自动定义一个无参的默认构造函数的,它不对成员属性做任何操作,如果我们自己定义了构造函数,系统就不会为我们创建默认构造函数了
析构函数
析构函数作用域构造函数相反,一般是执行对象的清理工作,当对象的生命周期结束的时候,会自动调用。析构函数的作用并不是删除对象,在对象撤销它所占用的内存之前,做一些清理工作。这部分内存就可以被系统回收再利用了。在设计这个类的时候,系统也会默认的提供一个析构函数。在对象的生命周期结束的时候,程序就会自动执行析构函数来完成这些工作。同构造函数,用户自己定义,系统自动调用。
- 析构函数没有返回值,没有参数;
- 没有参数,所以不能重载,一个类仅有一个析构函数;
- 析构函数除了释放工作,还可以做一些用户希望它做的一些工作
- 命名规则: ~类名()
其余:
C++的模板类:C++ template
C++的符号重载:operator
C++移动构造函数:移动构造函数
4.Android中的原子操作函数
定义在system/core/libcutils/Atomic.c,依赖于具体的芯片平台。原子操作函数特点:线程安全,返回旧值。
函数 | 作用 |
---|---|
int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) | 加函数,返回旧值,*ptr = *ptr + increment |
int32_t android_atomic_inc(volatile int32_t *addr) | 自增操作,返回旧值,*ptr = *ptr + 1 |
int32_t android_atomic_dec(volatile int32_t *addr) | 自减操作, 返回旧值,*ptr = *ptr - 1 |
int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) | 位与操作,返回旧值,*ptr = *ptr & value |
int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) | 位或操作,返回旧值,*ptr = *ptr |
int android_atomic_cmpxchg(int32_t old_value, int32_t new_value, volatile int32_t *ptr) | 如果addr == oldvalue,就会执行addr = new_value的操作,然后返回0,否则返回1 |
5.引用计数原理
引计数法是为了解决释放堆对象的引用,也就是指针对象。
下图是利用引用数管理对象释放的原理图:
引用计数的原理很简单,当引用某个对象时,使其引用数+1;引用结束时,使其引用数-1;当引用数为0时,delete掉实际对象。
问题:
上面这种简单的对象引用计数存在缺陷。比如说,A和B互相引用,在这种情况下,会造成A和B都无法释放。针对这种问题,对引用计数改进
改进
改进后的引用计数法,将引用计数分为强引用计数和弱引用计数。对象的生命周期只受强引用计数控制。
这种情景下,将有关联的对象分为“父 - 子”和“子 - 父”关系。 “父”对象通过强引用计数来引用“子”对象,“子”对象通过弱引用计数来引用“父”对象。 也就是说,父对象不受子对象的引用约束,父对象可以随时释放。但子对象不可释放。同时需要注意,如果子对象通过弱引用计数来访问父对象,不能直接访问,因为此时父对象可能被释放,所以需要一个弱引用转强引用的过程。
6.Android智能指针实现概述
Android智能指针提供了3种类型的智能指针,分别为轻量级指针,强指针,弱指针。轻量级指针使用的简单的引用计数技术。强指针和弱指针使用了强引用和弱引用技术。
无论是轻量级指针,还是强弱指针,它们的实现原理都是类似的。Android系统将引用计数器定义为一个公共类,所有支持智能指针的对象类(RefBase),都必须要从这个公共类继承下去。这样,Android系统的智能指针就可以通过这个引用计数器来维护对象的生命周期了。
三.强指针SP
强指针就是我们上面说的改进版的引用计数中,强引用的实现,现在让我们看看他的实现
目录:system/core/libutils/include/utils/StrongPointer.h
1.sp的定义
class sp {
public:
//构造函数
inline sp() : m_ptr(0) { }
sp(T* other); // NOLINT(implicit)
sp(const sp<T>& other);
sp(sp<T>&& other); //这里C++11中的移动构造函数
template<typename U> sp(U* other); // NOLINT(implicit)
template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
//析构函数
~sp();
//赋值号重载
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;
}
sp的定义,分为几部分:
- sp类一个模板类
- 类型T,U是指针类型的类型
- 有7个构造函数
- 6个“=”的重载
- 宏COMPARE的6个函数都是运算符的重载
- m_ptr就是指针变量,后面的所有操作都是通过这个来
2.构造函数的实现
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);//如果构造函数形参的指针不为null,该指针的计数加1
}
template<typename T>
sp<T>::sp(const sp<T>& other)//实参为sp<T>类型的对象,这里形参为引用
: 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> template<typename U>
sp<T>::sp(U* other)
: m_ptr(other) {
if (other)
(static_cast<T*>(other))->incStrong(this);
}
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
: m_ptr(other.m_ptr) {
if (m_ptr)
m_ptr->incStrong(this);
}
template<typename T> template<typename U>
sp<T>::sp(sp<U>&& other)
: m_ptr(other.m_ptr) {
other.m_ptr = nullptr;
}
在构造函数时,主要负责两件事:
- 初始化sp中关键的指针m_ptr,也就是实参的指针
- m_ptr也就是实参指针必须要调用incStrong()进行计数加1
关于incStrong()和decStrong暂时理解为指针m_ptr的计数加1和减1,后面会详解
3.析构函数
template<typename T>
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
在这里,m_ptr的计数加1和减1
4.赋值运算符的重载
template<typename T>
sp<T>& sp<T>::operator =(const sp<T>& other) {
// Force m_ptr to be read twice, to heuristically check for data races.
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
T* otherPtr(other.m_ptr);
if (otherPtr) otherPtr->incStrong(this);
if (oldPtr) oldPtr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = otherPtr;
return *this;
}
template<typename T>
sp<T>& sp<T>::operator =(sp<T>&& other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
if (oldPtr) oldPtr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
return *this;
}
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
if (other) other->incStrong(this);
if (oldPtr) oldPtr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = other;
return *this;
}
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(const sp<U>& other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
T* otherPtr(other.m_ptr);
if (otherPtr) otherPtr->incStrong(this);
if (oldPtr) oldPtr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = otherPtr;
return *this;
}
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(sp<U>&& other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
if (m_ptr) m_ptr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
return *this;
}
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(U* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
if (other) (static_cast<T*>(other))->incStrong(this);
if (oldPtr) oldPtr->decStrong(this);
if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
m_ptr = other;
return *this;
}
注意
- 6个赋值函数,或者叫6个 “=” 的重载中注意的是原来的decStrong 和新的指针的incStrong。
6.获取指针
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
7.其他的函数
//特殊需要用,一般不会用到
template<typename T>
void sp<T>::force_set(T* other) {
other->forceIncStrong(this);
m_ptr = other;
}
//做sp rest功能使用,会将指针的计数减1,指针置为空指针,注意C++11上用nullptr
template<typename T>
void sp<T>::clear() {
if (m_ptr) {
m_ptr->decStrong(this);
m_ptr = 0;
}
}
//这个是private函数,wp在做promote的时候会使用到,wp通过friend方式调用到这里。
template<typename T>
void sp<T>::set_pointer(T* ptr) {
m_ptr = ptr;
}
四.弱指针WP
上面我们看来SP即强引用的实现,接下来让我们看看弱引用的实现
目录:system/core/libutils/include/utils/RefBase.h
1.wp的定义
class wp
{
public:
typedef typename RefBase::weakref_type weakref_type;
inline wp() : m_ptr(0) { }
wp(T* other); // NOLINT(implicit)
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
template<typename U> wp(U* other); // NOLINT(implicit)
template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
~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;
};
wp和sp定义的比较:
- 都是模板类
- 都有7个构造函数和6个赋值重载函数
- 因为多了成员变量m_refs,所以,比较运算符进行了重载,sp没有m_refs,所以直接使用宏COMPARE_WEAK
- 都有指针T* m_ptr
- wp多了一个promte函数,为了向sp转换
- wp并没有sp中的重载运算符* 和 运算符 ->
2.构造函数
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T>
wp<T>::wp(const wp<T>& other)
: m_ptr(other.m_ptr), m_refs(other.m_refs)
{
if (m_ptr) m_refs->incWeak(this);
}
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
template<typename T> template<typename U>
wp<T>::wp(U* other)
: m_ptr(other)
{
if (other) m_refs = other->createWeak(this);
}
template<typename T> template<typename U>
wp<T>::wp(const wp<U>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = other.m_refs;
m_refs->incWeak(this);
}
}
template<typename T> template<typename U>
wp<T>::wp(const sp<U>& other)
: m_ptr(other.m_ptr)
{
if (m_ptr) {
m_refs = m_ptr->createWeak(this);
}
}
小结:
- 首先可以看出wp是通过createWeak 、incWeak、decWeak来控制,而不是 sp那样通过incStrong 和decStrong方式控制计数。这几个函数的具体作用,后面会有分析。
- 并没有像 sp那样有移动构造函数,为什么呢?
3.析构函数
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
这里通过decWeak释放引用
4.赋值运算符的重载
wp<T>& wp<T>::operator = (T* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0; //wp 中指针other通过createWeak创建,m_refs
if (m_ptr) m_refs->decWeak(this); //原来的m_refs需要decWeak
m_ptr = other;
m_refs = newRefs;
return *this;
}
template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
{
weakref_type* otherRefs(other.m_refs);
T* otherPtr(other.m_ptr);
if (otherPtr) otherRefs->incWeak(this);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = otherRefs;
return *this;
}
template<typename T>
wp<T>& wp<T>::operator = (const sp<T>& other)
{
weakref_type* newRefs =
other != NULL ? other->createWeak(this) : 0;/同形参为T* other,需要createWeak
T* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = newRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (U* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : 0;
if (m_ptr) m_refs->decWeak(this);
m_ptr = other;
m_refs = newRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const wp<U>& other)
{
weakref_type* otherRefs(other.m_refs);
U* otherPtr(other.m_ptr);
if (otherPtr) otherRefs->incWeak(this);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = otherRefs;
return *this;
}
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const sp<U>& other)
{
weakref_type* newRefs =
other != NULL ? other->createWeak(this) : 0;
U* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
m_refs = newRefs;
return *this;
}
通过赋值运算符重载看到,一般的指针在使用wp时,需要createWeak,如果已经是wp引用,直接incWeak
5.promote
通过 result.set_pointer,将弱指针变成强指针。
sp<T> wp<T>::promote() const
{
sp<T> result;
if (m_ptr && m_refs->attemptIncStrong(&result)) {
result.set_pointer(m_ptr);
}
return result;
}
6.遗留问题
看了sp和wp的实现 , 来盘点一下遗留的问题
- sp中decStrong 和incStrong的具体实现是什么?为什么控制指针的计数?
- wp 中m_refs 到底是什么意思?
- 构造或者是赋值的时候,为什么指针用的是createWeak,而m_refs 用的是incWeak 和decWea?
- wp称为弱指针也可以,确切的看并没有看到指针使用的地方,那wp如何使用?
带着这个问题来看看RefBase
六.RefBase
前面我们说过,sp和wp都是模板类,模板参数T或者U,构造函数或者重载运算符的函数中形参看到的是T * 、 U *,或者是sp &、wp &,好像和RefBase 有什么关系。但是,看完Android 中使用sp 和 wp的地方就知道,传进来的模板参数都是继承自RefBase,所谓的指针类型都是基于这个类。
接下来让我们看看RefBase的实现
目录:system/core/libutils/include/utils/RefBase.h
1.RefBase的定义
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;
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;
};
小结:
- 在sp 中看到的指针m_ptr都是通过incStrong 和decStrong 来控制计数,最终调用的就是这里的
- 在wp 中的m_refs的类型是weakref_type类型的指针
- weakref_type提供了incWeak,decWeak,attemptIncStrong,attemptIncWeak来维护对象的强引用计数和弱引用计数
- RefBase的关键是mRefs,类型为weakref_impl *,weakref_impl 实现weakref_type中提供的接口
2.构造函数
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
只有一个默认的构造函数,就是为了初始化mRefs,也就是说,以后RefBase的派生类在构造的时候,都会有个mRefs的指针变量。
3.weakref_impl
weakref_impl类的实现,有调试版和非调试版两个版本,他们是通过DEBUG_REFS来区别的,它的调试版本是用来调试他们本身的实习的,我们不需要关心,因此省略这些代码。
weakref_impl代码比较长,我们分段来看
定义和构造函数,析造函数
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;//
#if !DEBUG_REFS
.....
#else
//构造函数
weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)//默认强引用计数为1<<28
, mWeak(0)//默认弱引用计数为0
, mBase(base)//RefBase,也就是后来的指针,注意,后来weakref_impl需要delete的时候,这里mBase 也需要delete
, 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);
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);
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
CallStack stack(LOG_TAG);
}
}
....
}
提供的方法
class RefBase::weakref_impl : public RefBase::weakref_type
{
...
//强引用的指针地址会做为id存放在mStrongRefs链表中
void addStrongRef(const void* id) {
//ALOGD_IF(mTrackEnabled,
// "addStrongRef: RefBase=%p, id=%p", mBase, id);
addRef(&mStrongRefs, id, mStrong.load(std::memory_order_relaxed));
}
//根据id删除引用
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.load(std::memory_order_relaxed));
}
}
//更改id
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);
}
//将弱引用的指针作为id存放链表mWeakRefs中
void addWeakRef(const void* id) {
addRef(&mWeakRefs, id, mWeak.load(std::memory_order_relaxed));
}
void removeWeakRef(const void* id) {
if (!mRetain) {
removeRef(&mWeakRefs, id);
} else {
addRef(&mWeakRefs, id, -mWeak.load(std::memory_order_relaxed));
}
}
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];
snprintf(buf, sizeof(buf),
"Strong references on RefBase %p (weakref_type %p):\n",
mBase, this);
text.append(buf);
printRefsLocked(&text, mStrongRefs);
snprintf(buf, sizeof(buf),
"Weak references on RefBase %p (weakref_type %p):\n",
mBase, this);
text.append(buf);
printRefsLocked(&text, mWeakRefs);
}
{
char name[100];
snprintf(name, sizeof(name), 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));
}
}
...
}
单链表的实现
class RefBase::weakref_impl : public RefBase::weakref_type
{
...
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;
}
}
//根据id删除引用
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);
}
}
//更改id
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 ? '+' : '-';
snprintf(buf, sizeof(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
}
可以看出,weakref_impl是通过两个链表来维护该对象的强引用计数和弱引用计数。后面看看RefBase实现wp和sp控制引用计数的方法
4.sp的incStrong()和decStrong()
先看看incStrong
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->incWeak(id); //添加到弱引用链表
refs->addStrongRef(id);//添加到强引用链表中
//获取
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);//计数器+1
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;
}
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);
refs->mBase->onFirstRef();//调用onFirstRef()
}
在incStrong主要做了3件事
- 将指向的对象添加到弱引用链表中(增加了弱引用计数)
- 将指向的对象添加到强引用链表中(增加了强引用计数)
- 如果是第一次增加强引用,通知onFirstRef()处理一下业务逻辑
然后看看decStrong
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
//删除链表中对应的节点
refs->removeStrongRef(id);
//计数器-1
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);
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.
}
}
//删除弱引用链表
refs->decWeak(id);
}
在decStrong也主要做了三件事
- 将指向对象从强引用链表中删除(减少了弱引用计数)
- 将指向对象从弱引用链表中删除(减少了强引用计数)
- 如果此时强引用计数=0,则通知onLastStrongRef,处理业务逻辑。如果该对象不受弱引用影响,则释放该对象
5.wp的incWeak()和decWeak()
先看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 __unused = impl->mWeak.fetch_add(1,
std::memory_order_relaxed);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
weakref_type比较简单,将指向对象放入弱引用链表中,同时引用数+1
再看看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 = impl->mWeak.fetch_sub(1, std::memory_order_release);//引用计数-1
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) {
//强引用未使用(一般不可能发生)
if (impl->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
ALOGW("RefBase: Object at %p lost last weak reference "
"before it had a strong reference", impl->mBase);
} else {
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
//释放impl
delete impl;
}
//受强计数和弱计数的双重影响
} else {
impl->mBase->onLastWeakRef(id);
delete impl->mBase;
}
}
在也主要做了两件事
- 将指向对象从弱引用链表中删除(减少了强引用计数)
- 如果此时强引用计数=0,根据flags判断释放该对象
6.析构函数
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;
}
在析构函数中,主要是负责销毁mRefs
七.LightRefBase
android中除了RefBase,还有个轻量级的引用LightRefBase,如果只是想通过计数方式使用只能指针,也可以用LightRefBase。
目录:system/core/libutils/include/utils/LightRefBase.h
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;
};
整个定义来看,就一个核心变量mCount,为什么这里有incStrong、decStrong,就是为了后面使用sp准备。
LightRefBase的特点:
- LightRefBase 同RefBase一样,必须是某个指针的基类
- LightRefBase 轻量级引用,采用的是模板机制,而不是复杂的OOP,不需要虚拟继承
- 轻量级引用基类轻在内存,只拥有一个成员变量,用以计数。其引用计数类模板不含有虚函数,如果尾端类(不被其他类继承的类)直接继承引用计数基类,那尾端类也不需要虚的析构函数,不会出现因部分删除而产生内存泄露,因为模板类代码中有一处使用static_cast向下转型,模板确保其安全。
- RefBase持有弱引用,持有指针,在进行删除工作时较为复杂。
八.参考资料
《深入理解android 卷一》
《Android源码情景分析》
Android 智能指针详解 – sp
Android 智能指针详解 – wp
Android 智能指针详解 – RefBase