概述
java提供了垃圾回收机制,不需要程序员自己手动释放对象,c++对于堆上创建的对象需要手动delete,对于庞大的Android系统来说,对象实在容易因为各种原因被忘记释放,造成内存泄露,所以Android提供了一种智能指针来帮助对象释放,sp强指针,wp弱指针。
主要的类
智能指针主要涉及如下几个类:
/system/core/libutils/RefBase.cpp
/system/core/include/utils/RefBase.h
/system/core/libutils/include/utils/StrongPointer.h
Android native层有大量的sp类型对象,想要具有自动释放对象的类必须继承RefBase基类,看一下RefBase.h定义了哪些方法
RefBase.h
RefBase主要提供了增加强引用和减少强引用,还有个内部类,这个内部类才是主要管理对象引用计数的核心
class RefBase
{
public:
void incStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
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);
bool attemptIncWeak(const void* id);
int32_t getWeakCount() const;
};
RefBase.cpp
先看构造函数,构造函数中创建了weakref_impl,这是weakref_type具体实现类,用来管理对象的引用计数
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
}
RefBase析构
RefBase::~RefBase()
{
//获取mFlags的值
int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
//如果是弱引用控制
if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
//如果弱引用等于0
if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
//删除对象的weakref_impl
delete mRefs;
}
//如果没有增加强引用,mStrong初始化时为INITIAL_STRONG_VALUE
} else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
//什么都不做
}
//最终将weakref_impl置为空
const_cast<weakref_impl*&>(mRefs) = nullptr;
}
atomic是模板类,对一系列数据进行原子操作,这里mStrong,mWeak,mFlags都是int类型的
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;
//注意,这里面的方法是debug版本才会有的,正式版本不用关注
#if !DEBUG_REFS
explicit 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 renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
#else
weakref_impl(RefBase* base)
//#define INITIAL_STRONG_VALUE (1<<28)
//给强引用初始化值为1<<28
: mStrong(INITIAL_STRONG_VALUE)
//弱引用为0
, mWeak(0)
//base指向创建智能指针的具体对象
, mBase(base)
//mFlags为0,
, mFlags(0)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
, mRetain(false)
{
}
说一下mFlages,有三个类型,
OBJECT_LIFETIME_STRONG:强引用控制,当强引用计数为0,不管弱引用计数为多少都会释放对象。
OBJECT_LIFETIME_WEAK:弱引用控制,当强引用和弱引用为0才会释放对象。
OBJECT_LIFETIME_MASK:需要手动释放对象。
默认值为OBJECT_LIFETIME_STRONG,可以通过extendObjectLifetime进行修改。
enum {
OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
StrongPointer.h
sp构造对象的四种方式,两种括号两种等于号
//方式1
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
if (other)
other->incStrong(this);
}
//方式2
template<typename T>
sp<T>::sp(const sp<T>& other)
: m_ptr(other.m_ptr) {
if (m_ptr)
m_ptr->incStrong(this);
}
//方式3
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;
}
//方式4
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;
}
祁构函数:
sp<T>::~sp() {
if (m_ptr)
m_ptr->decStrong(this);
}
在Android源码中创建强指针往往会以下面的形式:
//方式2
sp<ProcessState> proc(ProcessState::self());
//方式4
sp<ProcessState> proc = new ProcessState();
方式2
//方式2
template<typename T>
sp<T>::sp(const sp<T>& other)
//m_ptr指向具体的引用对象
: m_ptr(other.m_ptr) {
if (m_ptr)
m_ptr->incStrong(this);
}
当m_ptr不为0则会调用对象的incStrong方法增加强引用计数1
incStrong
增加强引用计数
void RefBase::incStrong(const void* id) const
{
//在初始化具体的强引用对象时在Refbase构造函数中
//创建weakref_impl,赋值为mRefs
weakref_impl* const refs = mRefs;
//弱引用计数加1
refs->incWeak(id);
//前面说过,debug版本实现,正是版本为空
refs->addStrongRef(id);
//c++11的API,原子+1操作,返回+1之前的值
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
//在初始化具体对象时mStrong赋初值为INITIAL_STRONG_VALUE
//如果c在+1之前不为INITIAL_STRONG_VALUE,说明不是第一次增加强引用
//直接return,不执行后面操作
if (c != INITIAL_STRONG_VALUE) {
return;
}
//c++11的API,mStrong执行减INITIAL_STRONG_VALUE的操作
//相当于mStrong = INITIAL_STRONG_VALUE+1-INITIAL_STRONG_VALUE = 1
int32_t old __unused = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE, std::memory_order_relaxed);
//第一次增加强引用时调用onFirstRef方法
refs->mBase->onFirstRef();
}
incWeak
增加弱引用计数,这个方法很简单,弱引用计数加一
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);//debug版本方法
//c++11 API,原子操作+1
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);
}
可以看到incStrong主要做的事为强引用加1,弱引用加1,并且如果是首次增加强引用时调用对象的onFirstRef方法
sp的几种初始化方法中无非都是调用了incStrong和decStrong,在使用sp的=重载操作符时都会调用前一个对象的decStrong函数减少强引用(如果有之前的对象的话)。
decStrong
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
refs->removeStrongRef(id); //debug版本实现
//c++11 API,mStrong原子操作-1
const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);
//如果减1之前等于1,说明此时强引用为0
if (c == 1) {
//线程同步
std::atomic_thread_fence(std::memory_order_acquire);
//调用具体对象如ProcessState的onLastStrongRef方法
refs->mBase->onLastStrongRef(id);
//c++11 API,获取mFlags的值
int32_t flags = refs->mFlags.load(std::memory_order_relaxed);
//当mFlags为强引用控制时,默认为强引用控制
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { //直接释放对象
delete this;
}
//无论如何都会减少弱引用计数
refs->decWeak(id);
}
decWeak
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);//debug版本实现,release为空
//c++11 API,弱引用减1
const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
//当弱引用减1之前为不为1,说明弱引用减1之后还不会为0
//则return,不执行后面代码,仅仅弱引用减1就行了
if (c != 1) return;
//线程同步
atomic_thread_fence(std::memory_order_acquire);
//获取mFlags的值
int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
//当mFlags为强引用控制
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
//获取mStrong的值,如果等于INITIAL_STRONG_VALUE,说明
//此对象没有添加强引用,因为mStrong的初始值就是INITIAL_STRONG_VALUE
if (impl->mStrong.load(std::memory_order_relaxed)
== INITIAL_STRONG_VALUE) {
//什么都不做,这里在Android O之后修改过,之前是会释放对象的
//delete impl->mBase;
} else {
//添加过强引用则释放weakref_impl对象
delete impl;
}
} else {
//当mFlags为弱引用控制时,调用对象onLastWeakRef方法
impl->mBase->onLastWeakRef(id);
//释放对象
delete impl->mBase;
}
}
decStrong主要做的事就是强引用减1,弱引用减1,
当强引用为0并且mFlags为强引用控制时释放对象,
decWeak中会对弱引用减为0之后做一些判断,当mFlags为强引用控制并且对象没有添加过强引用则什么都不做,当mFlags为强引用控制并且对象有添加过强引用则释放weakref_impl,当mFlags为弱引用控制则调用对象onLastWeakRef方法并且释放对象
理解sp主要需要理解这几个增加减少强弱引用的方法,sp创建时强弱引用+1,sp析构的时候强弱引用-1,在根据mFlags来决定当强弱引用为0时是否释放对象,
mFlags为强引用控制时只要强引用为0则释放对象,当mFlags为弱引用控制时,只有强弱引用都为0才释放对象。
wp
wp初始化方法的几种方式中都是调用的几个方法decWeak,incWeak,createWeak,前面两个已经分析过
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}
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<T>::operator = (T* other)
{
weakref_type* newRefs =
other ? other->createWeak(this) : nullptr;
if (m_ptr) m_refs->decWeak(this);
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;
}
createWeak
这个方法里面调用incWeak,弱引用+1
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
mRefs->incWeak(id);
return mRefs;
}
wp析构函数
也很简单,弱引用-1,之前分析过了
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
其实Android智能指针对对象内存管理核心就是这几个方法,增加强引用(incStrong),减少强引用(decStrong),增加弱引用(incWeak),减少弱引用(decWeak)。
当对象创建为sp强指针时在sp的构造函数中调用对象的incStrong,incStrong中调用incWeak,最终结果强引用+1,弱引用+1,在出了sp作用域之后调用sp的析构函数,析构函数中调用对象的decStrong,decStrong中调用decWeak,最终结果强引用-1,弱引用-1,然后会根据mFlags判断以何种方式释放对象,再来回顾一下mFlags的值:
enum {
//强引用控制:当强引用为0就释放对象,不管弱引用
OBJECT_LIFETIME_STRONG = 0x0000,
//弱引用控制:当强弱引用都为0才释放对象
OBJECT_LIFETIME_WEAK = 0x0001,
//不主动释放对象,需要手动释放
OBJECT_LIFETIME_MASK = 0x0001
};
弱指针wp的存在意义有是什么呢?
按理说我们要管理c++内存对象有一个强指针sp就行了,为何还需要弱指针wp,先看一段代码:
class Student : public RefBase {
public:
Student() {
printf("Construct Student......");
}
~Student() {
printf("Destory Student......");
}
void setTeacher(sp<Teacher> teacher) { mTeacher = teacher; }
private:
sp<Teacher> mTeacher;
};
class Teacher : public RefBase {
public:
Teacher() {
printf("Construct Teacher......");
}
~Teacher() {
printf("Destory Teacher......");
}
void setStudent(sp<Student> student) { mStudent = student; }
private:
sp<Student> mStudent;
};
int main(int argc, char** argv)
{
Student* student = new Student();
Teacher* teacher = new Teacher();
{
sp<Student> student_sp = student;
sp<Teacher> teacher_sp = teacher;
teacher->setStudent(student);
student->setTeacher(teacher);
}
return 0;
}
创建了两个类Student和Teacher,都继承自RefBase,具有对象内存管理功能,首先分别对两个类创建sp,此时Student和Teacher的强弱引用分别+1,接着分别调用对方的set方法,Set方法里又创建sp,Student和Teacher的强弱引用再+1,Student和Teacher相互持有对方强引用,此时Student和Teacher的强弱引用都为2,当大括号作用域结束之后,调用sp析构函数,前面分析了sp析构函数中会将强弱引用-1,但是此时Student和Teacher还相互引用着,所以sp强弱引用都不为0,导致这两个对象无法释放。
修改一下代码:将Student持有Teacher的引用改为弱引用,
class Student : public RefBase {
public:
Student() {
printf("Construct Student......");
}
~Student() {
printf("Destory Student......");
}
void setTeacher(wp<Teacher> teacher) { mTeacher = teacher; }
private:
wp<Teacher> mTeacher;
};
class Teacher : public RefBase {
public:
Teacher() {
printf("Construct Teacher......");
}
~Teacher() {
printf("Destory Teacher......");
}
void setStudent(sp<Student> student) { mStudent = student; }
private:
sp<Teacher> mStudent;
};
int main(int argc, char** argv)
{
Student* student = new Student();
Teacher* teacher = new Teacher();
{
sp<Student> student_sp = student;
sp<Teacher> teacher_sp = teacher;
teacher->setStudent(student);
student->setTeacher(teacher);
}
return 0;
}
构造Student的sp,Student的强弱引用+1,构造Teacher的sp,Teacher的强弱引用+1,继续相互调用set方法,Teacher持有Student的强引用,Student的强弱引用+1,Student持有Teacher弱引用,Teacher的弱引用+1,此时Student的强弱引用为2,Teacher的强引用为1,弱引用为2,sp大括号结束,sp释放,调用incStrong,Student和Teacher的强弱引用-1,此时Teacher的强引用为0,弱引用为1,由于mFlags默认为:所以此时Teacher释放,Teacher释放后不再持有Student的强引用,Student强引用减为0,最终Student也得到释放。
//强引用控制:当强引用为0就释放对象,不管弱引用
OBJECT_LIFETIME_STRONG = 0x0000,
总结:wp可以用来解决对象相互引用的问题。