Android 智能指针

1 背景

cpp 开发中,指针是比较难处理,如果是一个大系统,管理不善很可能出现内存泄漏(new之后没释放)/野指针(已释放,但还有其他再使用)等问题发生。

java 使用引用的方式,不开放指针的操作,所以java side基本没这个问题。

有效解决上述问题的方式,andorid 设计一套方法(智能指针)自动管理指针的释放和引用情况,同时内部借助引用计数的方式解决在还有人使用时不释放指针(引用计数变为0时,才会析构指针所指对象)。

这边还一个问题是相互引用的情况,这样引用个数都不为0,就都不能释放了。所以android 设计了强引用sp和弱引用wp,向java取经。

2 sp/wp 定义

android 的封装的只能指针是sp/wp(strong pointer/weak pointer)。

code 路径是:

system/core/libutils/include/utils/RefBase.h

system/core/libutils/include/utils/StrongPointer.h

sp 和wp是模板类,模板的实现部分必须在header文件(*.h)中

看下图,

sp和wp就是封装了m_ptr指针,然后重载了一些操作符,并提供了clear/set等少部分api。

二者的不同点是,wp明显多了部分内容,就是weakref_type和与之相关的一些api

typedef typename RefBase::weakref_type weakref_type;

weakref_type就是RefBase::weakref_type。

后面再看 weakref_type的实现部分。

3 sp/wp 的实现

下面截取了部分sp和wp的实现部分,构造/析构/重载操作符等函数,基本实现都是一样的,都是调用的指针里面的操作,如incStrong/decStrong/createWeak/incWeak/decWeak。

但该指针是模板类型,所有这个指针模板就需要有一个公共父类,定义了上述的标准接口,才可以让sp和wp不会报错。   

system/core/libutils/include/utils/StrongPointer.h

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() {
    if (m_ptr)
        m_ptr->decStrong(this);
}

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;
}

system/core/libutils/include/utils/RefBase.h 

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)
{
    m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(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;
}

4  模板指针指向类:RefBase

想思考下为什么定义这个父类,一个原因是模板的写法定义统一的api,另一个原因是将引用计数统一放到这个父类中存储。

将引用计数存放到Refbase中,就是指针指向的实体中,如果在智能指针中就是单独计数了,因为每个智能指针是独立的,而指向的实体才是唯一的。

RefBase的结构体

看其构造和析构函数,new weakref_impl,weakref_impl是什么呢,看下图

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

RefBase::~RefBase()
    int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
    if ((flags & OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
        if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
            delete mRefs;
        }
    } else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
        ......
    }
    // For debugging purposes, clear mRefs.  Ineffective against outstanding wp's.
    const_cast<weakref_impl*&>(mRefs) = nullptr;
}

 weakref_impl 继承自weakref_type,扩展了部分接口,其实扩展的接口是debug使用的,只有打开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

然后看RefBase的incStrong的实现部分,

 system/core/libutils/RefBase.cpp

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);
    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 __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);
    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 和weakref_impl的相关实现,操作std::atomic<int32_t>进行+1。

incStrong 是将mStrong和mWeak 同时+1;当第一次调用时,则回调Refbase.onFirstRef()

同理decStrong 也是将mStrong和mWeak 同时-1, 最后一次调用时回调RefBase.onLastStrongRef().

void RefBase::decStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->removeStrongRef(id);
    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);
}

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);
    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(td::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);
            delete impl;
        }
    } else {
        // This is the OBJECT_LIFETIME_WEAK case. The last weak-reference
        // is gone, we can destroy the object.
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

5 wp的差异

观察wp 的实现code,与sp的差异点是,sp是直接使用ptr的incStrong/decStrong, wp则使用refs的incWeak/decWeak, 而Refbase中就没有提供incWeak/decWeak的接口,而是使用内部类weakref_impl提供这些接口。

为什么要这样处理呢?

因为Refbase和weakref_impl是可以脱离依托关系的,在Refbase被释放后,weakref_impl可以继续存在使用,所以wp使用weakref_impl 操作更安全。

6  delete的地方

从上面的code,可以看到

构造RefBase时,也new weakref_impl, 

那我们看Refbase和weakref_impl 是析构的呢,整理表格如下

RefBaseweakref_impl
OBJECT_LIFETIME_STRONGdecStrong且strong count =1decWeak且weak count为1,且strong count不为INITIAL_STRONG_VALUE
OBJECT_LIFETIME_WEAKdecWeak 且weak count =1RefBase 析构

Refbase和weakref_impl是可以脱离依托关系的, 在OBJECT_LIFETIME_STRONG模式下,当sp 对应的Refbase 释放后,weakref_impl继续存在,直到wp不在使用。

OBJECT_LIFETIME_WEAK 模式下,sp 不会控制RefBase的释放,在wp失效后,Refbase释放,接着weakref_impl释放。

7 weakref_impl 提供了debug 模式

在DEBUG_REFS 宏后,有debug模式存在,

它内部实现了一个链表,记录id和callstack,

这边需要通过api trackMe,设置mTrackEnabled = true

调用printRefs 可以将链表及callstack 信息输出到文件中

/data/debug/***.stack

【注意callstack 的code是在另一个so包中,"libutilscallstack", 如果打印callback 需要加上这个so,在apk/bin/或者相关so中奥】

    struct ref_entry
    {
        ref_entry* next;
        const void* id;
#if DEBUG_REFS_CALLSTACK_ENABLED && CALLSTACK_ENABLED
        CallStack::CallStackUPtr 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 && CALLSTACK_ENABLED
            ref->stack = CallStack::getCurrent(2);
#endif
            ref->next = *refs;
            *refs = ref;
        }
    }

    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;
            }

#if CALLSTACK_ENABLED
            CallStack::logStack(LOG_TAG);
#endif
        }
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值