1 sp介绍
智能指针(Smart Pointer)是一种用于管理动态分配的内存资源的工具,Android 提供了名为 sp 的智能指针类,也被称为强引用指针,用法和c++指针是一样的,但是sp指针可以根据引用计数来动态管理内存资源,普通指针则只能通过delete来释放内存资源
2 sp的使用
eg:
cpp
#include <utils/RefBase.h>
using namespace android;
class MyClass : public RefBase {
// ...
};
int main() {
sp<MyClass> obj = new MyClass();
// 使用 obj 智能指针来管理动态分配的对象
return 0;
}
1 这里的main函数我们创建了sp类型对象,属于栈对象,在作用域结束位置,会被自动释放
2 Myclass对象继承与RefBase类,RefBase是所有对象的基类,用于管理引用计数
3 sp的原理
抛出俩个问题
1 如何管理引用计数
2 如何通过引用计数判断引用的开始和结束
上述代码中我们构造了sp类型的栈对象
3.1 sp构造函数
StrongPointer.h
template<typename T>
class sp {
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
//sp类型对象构造函数 other不为空,赋值给m_ptr
//m_ptr会引用other指向的堆内存对象
if (other) {
check_not_on_stack(other);
//other指针指向的对象,基础refbase
//调用refbase的incStrong this指sp
other->incStrong(this);
}
}
}
可以看到sp是一个模板类,这里我们设置T为MyClass,首先会将指向MyClass的堆对象指针赋值给m_ptr,由此m_ptr也会引用MyClass的堆对象,调用other->incStrong(this)方法,增加引用计数,通过上述方法,我们知道在构造函数时会对引用计数进行增加,接下来分析引用计数的增加流程
3.2 RefBase::incStrong
other是Myclass对象的指针,Myclass继承与RefBase,incStrong是RefBase基类的方法
RefBase.cpp
void RefBase::incStrong(const void* id) const
{
//refs指向weakref_impl类型对象
weakref_impl* const refs = mRefs;
//将当前运行环境的标识符(id)加入到其弱引用计数器中
refs->incWeak(id);
refs->addStrongRef(id);
//使用原子操作将refs->mStrong+1返回旧值
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
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) {
//检查c不等于INITIAL_STRONG_VALUE 代表不是第一次引用
return;
}
int32_t old __unused = 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();
}
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
//原子操作将impl->mWeak +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);
}
在执行RefBase::incStrong,会让强引用计数器加1,弱引用计数器也会加1
3.3 sp析构
在前面我们构建了sp对象类型是MyClass,在sp对象作用域结束时,会调用sp对象的析构函数
StrongPointer.h
template<typename T>
sp<T>::~sp() {
if (m_ptr)
//如果m_ptr存在则减少引用计数
m_ptr->decStrong(this);
}
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
//将标识符id移除强引用计数器
refs->removeStrongRef(id);
//执行原子操作减少refs->mStrong的值
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) {
//case1 如果返回的旧值是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) {
//这里获取flags与OBJECT_LIFETIME_MASK与运算如果是强指针
//会执行delete从堆中释放该对象
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.
//
// Since we're doing atomic loads of `flags`, the static analyzer assumes
// they can change between `delete this;` and `refs->decWeak(id);`. This is
// not the case. The analyzer may become more okay with this patten when
// https://bugs.llvm.org/show_bug.cgi?id=34365 gets resolved. NOLINTNEXTLINE
//通过原子操作减少弱引用计数
refs->decWeak(id);
}
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);
//执行原子操作减少impl->mWeak的值
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);
//如果c != 1代表当前对象还在被引用中
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 {
//case2 至少存在一个强引用情况下
//释放引用计数器对象
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
// This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
// is gone, we can destroy the object.
//弱引用控制 执行onLastWeakRef回调
impl->mBase->onLastWeakRef(id);
//释放实际对象
delete impl->mBase;
}
}
m_ptr->decStrong来调用refbase的decStrong减少引用计数
再通过原子操作处理完mStrong引用计数器后,根据返回的旧值c
来判断当前是否为最后一次强引用
·不是的话就正常调用 refs->decWeak(id),尝试对弱引用计数器mWeak进行原子操作
是的话执行mBase->onLastStrongRef(id),执行最后一次引用的回调
再去delete对象,释放内存
也会执行 refs->decWeak(id)方法对弱引用计数器mWeak进行原子操作,判断当前是否为最后一次弱引用
是的话,检查flags是强引用控制还是弱引用控制
强引用控制的话
首先会判断case1 mStrong == INITIAL_STRONG_VALUE
这代表没有强引用引用过该对象,但是确存在弱引用,这属于异常情况会打印log提示
case2 mStrong != INITIAL_STRONG_VALUE 代表至少存在一个强引用情况下,那么会删除引用计数器对象
弱引用控制的话
那就执行 impl->mBase->onLastWeakRef(id)方法触发回调
delete实际对象释放内存
在sp最后一个引用下,释放实际对象后,会自动调用RefBase的析构函数
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) {
//flag为弱指针控制
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
//读取mWeak的值为0,表示没有任何弱引用指向对象,那么它会删除 mRefs 对象,即释放引用计数器对象的内存
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.
//flag为强指针控制 但是没有强引用引用过的异常情况,打印log
// TODO: make this fatal, but too much code in Android manages RefBase with
// new/delete manually (or using other mechanisms such as std::make_unique).
// However, this is dangerous because it's also common for code to use the
// sp<T>(T*) constructor, assuming that if the object is around, it is already
// owned by an sp<>.
ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
"object.",
mRefs->mWeak.load(), this);
#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
//设置mRefs为空指针 防止野指针出现
const_cast<weakref_impl*&>(mRefs) = nullptr;
}
在处理refbase的析构时,根据flag判断当前是弱引用控制还是强引用控制
弱引用控制当引用计数器的mWeak等于0时,可以delete引用计数器对象
强引用控制但是确从来没有强引用引用过的异常情况,会打印log
最后将mRefs指针置空防止野指针出现
回到上面我们提到的例子
#include <utils/RefBase.h>
using namespace android;
class MyClass : public RefBase {
// ...
};
int main() {
sp<MyClass> obj = new MyClass();
// 使用 obj 智能指针来管理动态分配的对象
return 0;
}
1 首先构造实际对象
2 先执行refbase的构造在执行sp的构造
3 执行incStrong方法先增加mweak弱引用计数再增加mstrong强引用计数
4 根据旧值判断是否第一次引用对象,触发onFirstRef回调
5 作用域结束,执行sp的析构函数
6 执行refbase的decStrong,根据原子操作减少mStrong强引用计数
7 根据旧值判断当前是否为最后一次强引用
8 是的话触发onLastStrongRef回调,释放实际对象
9 执行 refs->decWeak(id),减少mWeak弱引用计数
10 根据旧值确认是否为最后一次弱引用
11 是的话删除引用计数器对象
12执行父类refbase的析构函数,获取flag确认当前时强引用控制
13 mRefs置为空指针来防止野指针出现
4 wp的原理
因为sp在构造和析构时都会影响到弱引用计数器,所以下面内容会和sp有重复,只要明白了sp的原理,wp也很好理解
4.1 wp的例子
class MyClass : public RefBase {
// ...
};
int main() {
MyClass* myClass = new MyClass();
sp<MyClass> obj = new MyClass();
wp<MyClass> weakObj(obj); // 使用 obj 智能指针来管理动态分配的对象
return 0;
}
这里先指向sp的对象放入wp的构造函数中
4.2 wp的构造
RefBase.h
template<typename T>
wp<T>::wp(const sp<T>& other)
: m_ptr(other.m_ptr)
{
//指向m_ptr->createWeak(this)
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}
RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
//指向mRefs->incWeak(id);
mRefs->incWeak(id);
return mRefs;
}
void RefBase::weakref_type::incWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
//原子操作将impl->mWeak +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);
}
可以看到在弱引用的构造中只会通过原子操作调整mWeak的值
4.3 wp的析构
RefBase.h
template<typename T>
wp<T>::~wp()
{
if (m_ptr) m_refs->decWeak(this);
}
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->removeWeakRef(id);
//执行原子操作减少impl->mWeak的值
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);
//如果c != 1代表当前对象还在被引用中
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 {
//case2 至少存在一个强引用情况下可以理解为最后一次强引用下
//释放引用计数器对象
// ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
// This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
// is gone, we can destroy the object.
//弱引用控制 执行onLastWeakRef回调
impl->mBase->onLastWeakRef(id);
//释放实际对象
delete impl->mBase;
}
}
通过原子操作减少引用计数,根据旧值确认是否为最后一次弱引用,跟据flag确认当前是强引用控制,还是弱引用控制,这里是弱引用
所以执行impl->mBase->onLastWeakRef(id)回调函数,释放实际对象。
接下来调用父类的析构函数
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) {
//flag为弱指针控制
// It's possible that the weak count is not 0 if the object
// re-acquired a weak reference in its destructor
//读取mWeak的值为0,表示没有任何弱引用指向对象,那么它会删除 mRefs 对象,即释放引用计数器对象的内存
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.
//flag为强指针控制 但是没有强引用引用过的异常情况,打印log
// TODO: make this fatal, but too much code in Android manages RefBase with
// new/delete manually (or using other mechanisms such as std::make_unique).
// However, this is dangerous because it's also common for code to use the
// sp<T>(T*) constructor, assuming that if the object is around, it is already
// owned by an sp<>.
ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
"object.",
mRefs->mWeak.load(), this);
#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
//设置mRefs为空指针 防止野指针出现
const_cast<weakref_impl*&>(mRefs) = nullptr;
}
获取flag确认是弱引用控制,获取引用计数mWeak的值为0,释放引用计数器对象
5 轻量级指针原理
轻量级指针通过计数器的方式来动态管理对象的释放
5.1 轻量级指针代码
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(const void* id) const {
android_atomic_inc(&mCount);
}
inline void decStrong(const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}
typedef LightRefBase<T> basetype;
protected:
inline ~LightRefBase() { }
private:
friend class ReferenceMover;
inline static void moveReferences(void* d, void const* s, size_t n,
const ReferenceConverterBase& caster) { }
private:
mutable volatile int32_t mCount;
};
可以看到在轻量级指针通过mCount属性来进行计数的,通过IncStrong函数/decStrong函数来进行计数管理,在旧值为1,最后一次引用的情况会去delete目标对象
5.2 轻量级指针例子
#include <utils/LifeRefBase.h>
#include <utils/RefBase.h>
using namespace android;
class MyObject : public LifeRefBase<MyObject> {
public:
MyObject() {}
virtual ~MyObject() {}
};
int main() {
// 创建一个 MyObject 对象的智能指针
sp<MyObject> object = MyObject::make();
return 0;
}
可以看到我们创建MyObject对象继承LightRefBase,通过构建/析构目标类型的sp对象在适当时候执行LightRefBase中的incStrong/decStrong来调整引用计数值从而动态释放目标对象
5.3LightRefBase的痛点
LightRefBase的痛点在于无法处理循环引用问题
举例
#include <iostream>
#include <memory>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> bPtr;
A() {
std::cout << "A Constructor" << std::endl;
}
~A() {
std::cout << "A Destructor" << std::endl;
}
};
class B {
public:
std::shared_ptr<A> aPtr;
B() {
std::cout << "B Constructor" << std::endl;
}
~B() {
std::cout << "B Destructor" << std::endl;
}
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->bPtr = b; // A 持有 B 的智能指针
b->aPtr = a; // B 持有 A 的智能指针
return 0;
}
可以看到我们定义了A,B俩个类,A类中存在spbPtr,B类中存在spaPtr,在我们构建A,B俩个对象后,需要为bPtr和aPtr进行赋值。这时就存在了相互循环引用的情况,系统一次只能delete一个对象,如果出现循环引用那就没办法delete对象
5.4 循环引用的解决方法
上述讲解的sp,wp来解决循环引用
举例子
class A {
public:
std::shared_ptr<B> bPtr;
A() {
std::cout << "A Constructor" << std::endl;
}
~A() {
std::cout << "A Destructor" << std::endl;
}
};
class B {
public:
std::weak_ptr<A> aPtr;
B() {
std::cout << "B Constructor" << std::endl;
}
~B() {
std::cout << "B Destructor" << std::endl;
}
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->bPtr = b;
b->aPtr = a;
return 0;
}
在这里针对AB类的循环引用,将其中一个类的属性设置为wp类型,就可以解决上述循环引用问题,弱引用计数是不会影响强引用对象的释放,同时弱引用对象也不会导致强引用计数增加,这样在对象所在作用域执行完成后,正常执行sp对象析构操作,来释放实际对象
6 弱指针升级强指针
template<typename T>
sp<T> wp<T>::promote() const
{
sp<T> result;
//mptr不为空并且attemptIncStrong成功
if (m_ptr && m_refs->attemptIncStrong(&result)) {
//设置sp对象指向的目标对象
result.set_pointer(m_ptr);
}
return result;
}
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);
ALOG_ASSERT(curCount >= 0,
"attemptIncStrong called on %p after underflow", this);
//当前对象存在强引用,强引用计数+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.
//compare_exchange_weak 函数会将 impl->mStrong 的值与 curCount 进行比较
//,如果相等,则将 curCount+1 存储到 impl->mStrong 中,并返回 true;
//否则,将 impl->mStrong 的当前值存储到 curCount 中,并返回 false。
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 <= 0 || curCount == INITIAL_STRONG_VALUE) {
// we're now in the harder case of either:
// - there never was a strong reference on us
// - or, all strong references have been released
int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
//强引用控制
// this object has a "normal" life-time, i.e.: it gets destroyed
// when the last strong reference goes away
if (curCount <= 0) {
//最后一个强引用被删除,释放目标对象 那就减少弱引用计数
// the last strong-reference got released, the object cannot
// be revived.
decWeak(id);
return false;
}
// here, curCount == INITIAL_STRONG_VALUE, which means
// there never was a strong-reference, so we can try to
// promote this object; we need to do that atomically.
while (curCount > 0) {
//增加强引用计数
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 (e.g.: another thread has inc/decStrong'ed us)
// curCount has been updated.
}
if (curCount <= 0) {
// promote() failed, some other thread destroyed us in the
// meantime (i.e.: strong count reached zero).
//最后一个强引用被删除,释放目标对象 那就减少弱引用计数
decWeak(id);
return false;
}
} else {
//弱引用控制
// this object has an "extended" life-time, i.e.: it can be
// revived from a weak-reference only.
// Ask the object's implementation if it agrees to be revived
if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
//onIncStrongAttempted回调是否同意被恢复,
// it didn't so give-up.
//不同意 减少弱引用计数
decWeak(id);
return false;
}
// grab a strong-reference, which is always safe due to the
// extended life-time.
//增加强引用计数
curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
// If the strong reference count has already been incremented by
// someone else, the implementor of onIncStrongAttempted() is holding
// an unneeded reference. So call onLastStrongRef() here to remove it.
// (No, this is not pretty.) Note that we MUST NOT do this if we
// are in fact acquiring the first reference.
if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
//执行onLastStrongRef回调
impl->mBase->onLastStrongRef(id);
}
}
}
impl->addStrongRef(id);
#if PRINT_REFS
ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif
// curCount is the value of mStrong before we incremented it.
// Now we need to fix-up the count if it was INITIAL_STRONG_VALUE.
// This must be done safely, i.e.: handle the case where several threads
// were here in attemptIncStrong().
// curCount > INITIAL_STRONG_VALUE is OK, and can happen if we're doing
// this in the middle of another incStrong. The subtraction is handled
// by the thread that started with INITIAL_STRONG_VALUE.
if (curCount == INITIAL_STRONG_VALUE) {
//当前对象未被强引用
//在调用 decStrong 函数时,如果对象的强引用计数为 INITIAL_STRONG_VALUE,
//则表示当前并没有任何强引用指向该对象,因此需要将强引用计数设置为 0
impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
std::memory_order_relaxed);
}
return true;
}
弱指针的最大特点是它不能直接操作目标对象,这是怎么样做到的呢?秘密就在于弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。但是,如果我们要操作目标对象,应该怎么办呢,这就要把弱指针升级为强指针了
通过promote方法将弱指针升级为强指针
原理构建sp对象,执行attemptIncStrong尝试增加目标对象的弱引用计数,强引用计数,成功的话,设置sp对象内指针指向目标对象
这样promote方法返回的就是新引用目标对象的sp对象,就可以指向目标对象的方法
7 总结
-
Android中LightRefBase实现了基本的智能指针功能。
-
强指针和弱指针是为了解决循环引用中类死锁问题引起的内存泄露。
-
引用对象继承RefBase,则拥有了强引用计数和弱引用计数的属性。
-
通过extendObjectLifetime函数改变mFlags的值,确定对象受哪种引用计数影响。
-
调用incStrong增加强引用计数时,会同时增加强引用计数和弱引用计数,第一次增加强引用计数时,强引用计数从INITIAL_STRONG_VALUE改变为1。
-
调用incWeak增加弱引用计数时,只有弱引用计数增加,强引用计数不变。
-
弱引用计数≥强引用计数,强增弱必增,弱增强不一定增。
-
调用decStrong减少强引用指针时:
如果对象受强引用计数影响,强引用计数减1,如果此时强引用计数为0,不管弱引用计数是否为0,删除引用对象(此时由于弱引用计数还没减少,所以析构函数不会删除指针对象)。然后弱引用计数减1,如果此时弱引用计数也为0,则删除指针对象。
如果对象受弱引用计数影响,强引用计数减1,弱引用计数减1,如果此时弱引用计数为0,则删除引用对象,在引用对象的析构函数中会删除指针对象。
-
调用decWeak减少弱引用指针时:
如果对象受强引用计数影响,弱引用计数减1,如果此时弱引用计数为0,看看强引用计数,如果为INITIAL_STRONG_VALUE则说明没有强指针指向该对象,此时直接删除引用对象,指针对象也会随之删除。如果强引用计数不为INITIAL_STRONG_VALUE,则一定为0,因为强引用计数小于等于弱引用计数,此时只需要删除指针对象,因为强引用计数为0并且对象受强引用计数影响,所以对象已经被删除。
如果对象受弱引用计数影响,弱引用计数减1,如果此时弱引用计数为0,则删除引用对象,指针对象也随之删除。
-
强指针和弱指针是两个不同的类,引用对象时会以不同的方式改变强引用计数和弱引用计数的值。
-
强指针直接调用incStrong和decStrong,会同时增加或减少强引用计数和弱引用计数。弱指针调用createWeak进而调用incWeak,或者调用decWeak,只影响弱引用计数,不影响强引用计数。
-
弱指针不能直接操作目标对象,因为弱指针类没有重载*和->操作符号,而强指针重载了这两个操作符号。如果我们要操作目标对象,就要使用promote函数把弱指针升级为强指针。
-
弱指针转化为强指针不一定成功,如果可以转化则使用弱指针的m_ptr构造强指针
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题