Android Framework学习(六)之RefBase,SP,WP

3A之自动对焦(AF)算法:从Tenegrad到拉普拉斯的清晰度评价实战 本文深入解析自动对焦(AF)算法的核心——清晰度评价函数,通过实战对比Tenegrad、方差、能量梯度、Brenner和拉普拉斯五大经典算法的原理、代码实现与性能。文章详细阐述了各函数在计算速度、抗噪性和单峰性上的优劣,并提供了从仿真测试到硬件部署的优化策略,帮助开发者根据实际场景选择最合适的AF算法。 阅读详情

前言

Android中通过引用计数来实现智能指针,并且实现有强指针与弱指针。由对象本身来提供引用计数器,但是对象不会去维护引用计数器的值,而是由智能指针来管理。

要达到所有对象都可用引用计数器实现智能指针管理的目标,可以定义一个公共类,提供引用计数的方法,所有对象都去继承这个公共类,这样就可以实现所有对象都可以用引用计数来管理的目标,在Android中,这个公共类就是RefBase,同时还有一个简单版本LightRefBase。

RefBase作为公共基类提供了引用计数的方法,但是并不去维护引用计数的值,而是由两个智能指针来进行管理:sp(Strong Pointer)和wp(Weak Pointer),代表强引用计数和弱引用计数。 本篇博客我们就一起来学习RefBase,sp(Strong Pointer)和wp(Weak Pointer)。

轻量级引用计数的实现:LightRefBase

LightRefBase的实现很简单,只是内部保存了一个变量用于保存对象被引用的次数,并提供了两个函数用于增加或减少引用计数。

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:
    mutable volatile int32_t mCount;
};

sp(Strong Pointer)

LightRefBase仅仅提供了引用计数的方法,具体引用数应该怎么管理,就要通过智能指针类来管理了,每当有一个智能指针指向对象时,对象的引用计数要加1,当一个智能指针取消指向对象时,对象的引用计数要减1,在C++中,当一个对象生成和销毁时会自动调用(拷贝)构造函数和析构函数,所以,对对象引用数的管理就可以放到智能指针的(拷贝)构造函数和析构函数中。Android提供了一个智能指针可以配合LightRefBase使用:sp,sp的定义如下:

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }
    sp(T* other);
    sp(const sp<T>& other);

    template<typename U> sp(U* other);
    template<typename U> sp(const sp<U>& other);

    ~sp();

    // Assignment
    sp& operator = (T* other);
    sp& operator = (const sp<T>& other);

    template<typename U> sp& operator = (const 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;
};

其中Accessors部分代码重载了*、->操作符使我们使用sp的时候就像使用真实的对象指针一样,可以直接操作对象的属性或方法,COMPARE是宏定义,用于重载关系操作符,由于对引用计数的控制主要是由(拷贝)构造函数和析构函数控制,所以忽略其他相关代码后,sp可以精简为如下形式(赋值操作符也省略掉了,构造函数省略相似的两个):

template <typename T>
class sp
{
public:
    inline sp() : m_ptr(0) { }
    sp(T* other);
    sp(const sp<T>& other);

    ~sp();

private:  
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    T* m_ptr;
};

默认构造函数使智能指针不指向任何对象,sp(T* other)与sp(const sp& other)的实现如下:

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

内部变量m_ptr指向实际对象,并调用实际对象的incStrong函数,T继承自LightRefBase,所以此处调用的是LightRefBase的incStrong函数,之后实际对象的引用计数加1。

当智能指针销毁的时候调用智能指针的析构函数:

template<typename T>
sp<T>::~sp()
{
    if (m_ptr) m_ptr->decStrong(this);
}

调用实际对象即LightRefBase的decStrong函数,其实现如下:

inline void decStrong(const void* id) const {
    if (android_atomic_dec(&mCount) == 1) {
        delete static_cast<const T*>(this);
    }
}

android_atomic_dec返回mCount减1之前的旧值,如果返回1表示这次减过之后引用计数就是0了,就把对象delete掉。

RefBase

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;
        //! DEBUGGING ONLY: Enable tracking for this object.
        // enable -- enable/disable tracking
        // retain -- when tracking is enable, if true, then we save a stack trace
        //           for each reference and dereference; when retain == false, we
        //           match up references and dereferences and keep only the
        //           outstanding ones.
        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    = 0x0003
    };

    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);
    weakref_impl* const mRefs;
};

不同于LightRefBase中通过mCount保存对象被引用的次数,RefBase内部并没有使用一个变量来维护引用计数,而是通过一个weakref_impl *类型的成员mRefs来维护引用计数,并且同时提供了强引用计数和弱引用计数。weakref_impl继承于RefBase::weakref_type,代码比较多,不过大都是调试代码,由宏定义分开,Release是不包含调试代码的,去除这些代码后其定义为:

#define INITIAL_STRONG_VALUE (1<<28)

class RefBase::weakref_impl : public RefBase::weakref_type 
{ 
public: 
    volatile int32_t    mStrong; 
    volatile int32_t    mWeak; 
    RefBase* const      mBase; 
    volatile int32_t    mFlags; 

    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 addWeakRef(const void* /*id*/) { } 
    void removeWeakRef(const void* /*id*/) { } 
    void printRefs() const { } 
    void trackMe(bool, bool) { } 
};

weakref_impl中的函数都是作为调试用,Release版的实现都是空的,成员变量分别表示强引用数、弱引用数、指向实际对象的指针与flag,flag可控制实际对象的生命周期,取值为0或RefBase中定义的枚举值。

RefBase提供了incStrong与decStrong函数用于控制强引用计数值,其弱引用计数值是由weakref_impl控制,强引用计数与弱引用数都保存在weakref_impl *类型的成员变量mRefs中。

RefBase同LightRefBase一样为对象提供了引用计数的方法,对引用计数的管理同样要由智能指针控制,由于RefBase同时实现了强引用计数与弱引用计数,所以就有两种类型的智能指针,sp(Strong Pointer)与wp(Weak Pointer)。

sp采用了模版,它的(拷贝)构造函数调用实际对象的incStrong函数,由于所有实际对象都是继承自RefBase,所以查看RefBase的incStrong。

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id);
    refs->addStrongRef(id);
     //下面函数为原子加1操作,并返回旧值。所以c=0x1000000,而mStrong变为0x1000001
    const int32_t c = android_atomic_inc(&refs->mStrong);
    LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
    if (c != INITIAL_STRONG_VALUE)  {
    //如果c不是初始值,则表明这个对象已经被强引用过一次了
        return;
    }
    //下面函数为原子加1操作,并返回旧值。所以c=0x1000000,而mStrong变为0x1000001
    android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
     /*
   如果是第一次引用,则调用onFirstRef,这个函数很重要,派生类可以重载这个函数,完成一些
   初始化工作。
 */
    refs->mBase->onFirstRef();
}

addStrong的函数体为空,incStrong函数内部首先调用成员变量mRefs的incWeak函数将弱引用数加1,然后再将强引用数加1,由于android_atomic_inc返回变量的旧值,所以如果其不等于INITIAL_STRONG_VALUE就直接返回,则则是第一次由强智能指针(sp)引用,将其减去INITIAL_STRONG_VALUE后变成1,然后调用对象的onFirstRef。

成员变量mRefs是在对象的构造函数中初始化的:

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

weakrel_impl的incWeak继承自父类weakrel_type的incWeak:

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>
    impl->addWeakRef(id);
    const int32_t c = android_atomic_inc(&impl->mWeak);
    LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

addWeakRef实现同样为空,所以只是将弱引用计数加1。所以当对象被sp引用后,强引用计数与弱引用计数会同时加1。

当sp销毁时其析构函数调用对象即RefBase的decStrong函数:

void RefBase::decStrong(const void* id) const
{ 
    weakref_impl* const refs = mRefs; 
    refs->removeStrongRef(id); 
    const int32_t c = android_atomic_dec(&refs->mStrong);
    //注意,此时强弱引用计数都是1,下面函数调用的结果是c=1,强引用计数为0
    if (c == 1) { 
    //调用onLastStrongRef,表明强引用计数减为0,对象有可能被delete
        const_cast<RefBase*>(this)->onLastStrongRef(id);
         //mFlags为0,所以会通过delete this把自己干掉
         //注意,此时弱引用计数仍为1 
        if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 
            delete this; 
        }
    } 
    refs->removeWeakRef(id); 
    refs->decWeak(id); 
}

decStrong中将强引用数与弱引用数同时减1,如果这是最后一个强引用的话,会调用对象的onLastStrongRef,并且判断成员变量mRefs的成员变量mFlags来决定是否在对象的强引用数为0时释放对象。

mFlags可以为0或以下枚举值:

enum {
       OBJECT_LIFETIME_WEAK    =  0x0001,
       OBJECT_LIFETIME_FOREVER = 0x0003
};

注意:FOREVER的值是3,二进制表示是B11,而WEAK的二进制是B01,也就是说FOREVER包括了WEAK的情况。

mFlags的值可以通过extendObjectLifetime函数改变:

void RefBase::extendObjectLifetime(int32_t mode)
{
    android_atomic_or(mode, &mRefs->mFlags);
}

OBJECT_LIFETIME_FOREVER包含OBJECT_LIFETIME_WEAK(位运算中其二进制11包含01),所以当

refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK

为true时表示mFlags为0,实际对象的生命周期受强引用数控制,所以在强引用数为0时delete this,否则实际对象的生命周期就由弱引用数控制。

再来看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 = android_atomic_dec(&impl->mWeak); 
    if (c != 1) return; 

    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 
        if (impl->mStrong == INITIAL_STRONG_VALUE) 
            delete impl->mBase; 
        else { 
            delete impl; 
        } 
    } else { 
        impl->mBase->onLastWeakRef(id); 
        if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { 
            delete impl->mBase; 
        } 
    } 
}

将弱引用数减1,若减1后不为0直接返回,否则判断 (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK

实际对象生命周期被强引用数控制,接下来判断: mpl->mStrong == INITIAL_STRONG_VALUE

如果判断为true表示对象只被弱引用引用过,现在弱引用数为0,直接删除实际对象。

如果判断为false,表示对象曾经被强引用引用过,但现在强引用为变为0了(因为增加或减小强引用数时一定同时增加或减小弱引用数,所以弱引用数为0时,强引用数一定为0),弱引用数为0了,直接释放mRefs,而实际对象由于受强引用数控制,已经在RefBase::decStrong中被delete了。

若判断结果为false: 判断mFlgs是否是OBJECT_LIFETIME_FOREVER,如果是,什么都不作由用户自己控制对象的生命周期,否则,实际对象的生命周期受弱引用数控制,现在弱引用数为0,delete实际对象。

wp(Weak Pointer)

定义如下:

template <typename T>
class wp
{
public:
    typedef typename RefBase::weakref_type weakref_type;

    inline wp() : m_ptr(0) { }

    wp(T* other);
    wp(const wp<T>& other);
    wp(const sp<T>& other);
    template<typename U> wp(U* other);
    template<typename U> wp(const sp<U>& other);
    template<typename U> wp(const wp<U>& other);

    ~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(==)
    COMPARE(!=)
    COMPARE(>)
    COMPARE(<)
    COMPARE(<=)
    COMPARE(>=)

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;

    T*              m_ptr;
    weakref_type*   m_refs;
};

同sp一样,m_ptr指向实际对象,但wp还有一个成员变量m_refs。

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

RefBase::weakref_type* RefBase::createWeak(const void* id) const
{
    mRefs->incWeak(id);
    return mRefs;
}

可以看到,wp的m_refs就是RefBase即实际对象的mRefs。 wp析构的时候减少弱引用计数:

template<typename T>
wp<T>::~wp()
{
    if (m_ptr) m_refs->decWeak(this);
}

由于弱指针没有重载*与->操作符,所以不能直接操作指向的对象,虽然有unsafe_get函数,但像名字所示的,不建议使用,直接使用实际对象指针的话就没必要用智能指针了。

因为弱指针不能直接操作对象,所以要想操作对象的话就要将其转换为强指针,即wp::promote方法:

template<typename T>
sp<T> wp<T>::promote() const
{
    return sp<T>(m_ptr, m_refs);
}

template<typename T>
sp<T>::sp(T* p, weakref_type* refs)
    : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
{
}

是否能从弱指针生成一个强指针关键是看refs->attemptIncStrong,看其定义:

bool RefBase::weakref_type::attemptIncStrong(const void* id)
{
    incWeak(id);

    weakref_impl* const impl = static_cast<weakref_impl*>(this);

    int32_t curCount = impl->mStrong;
    LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
               this);
    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
            break;
        }
        curCount = impl->mStrong;
    }

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        bool allow;
        if (curCount == INITIAL_STRONG_VALUE) {
            // Attempting to acquire first strong reference...  this is allowed
            // if the object does NOT have a longer lifetime (meaning the
            // implementation doesn't need to see this), or if the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
                  || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        } else {
            // Attempting to revive the object...  this is allowed
            // if the object DOES have a longer lifetime (so we can safely
            // call the object with only a weak ref) and the implementation
            // allows it to happen.
            allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
                  && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
        }
        if (!allow) {
            decWeak(id);
            return false;
        }
        curCount = android_atomic_inc(&impl->mStrong);

        // 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) {
            impl->mBase->onLastStrongRef(id);
        }
    }

    impl->addWeakRef(id);
    impl->addStrongRef(id);

#if PRINT_REFS
    LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif

    if (curCount == INITIAL_STRONG_VALUE) {
        android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
        impl->mBase->onFirstRef();
    }

    return true;
}

首先通过incWeak将弱引用数加1(被强指针sp引用会导致强引用数和弱引用数同时加1),然后:

int32_t curCount = impl->mStrong;
while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
    if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
        break;
    }
    curCount = impl->mStrong;
}

如果之前已经有强引用,直接将强引用数加1,android_atomic_cmpxchg表示如果impl->mStrong的值为curCount,则把impl->mString的值改为curCount+1,此处用while循环是防止其他线程已经增加了强引用数。 接下来: if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) 表示对象目前没有强引用,这就要判断对象是否存在了。 如果curCount == INITIAL_STRONG_VALUE,表示对象没有被sp引用过。接下来判断:

allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
    || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

表示:如果对象的生命周期只受强引用控制,对象一定存在,要有强引用才可以管理对象的释放,所以一定会允许生成强引用;如果对象的生命周期受弱引用控制,调用对象的onIncStrongAttempted试图增加强引用,由于此时在弱引用中,弱引用一定不为0,对象也一定存在,调用onIncStrongAttempted的意图是因为类的实现者可能不希望用强引用引用对象。在RefBase中onIncStrongAttempted默认返回true:

bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
{
    return (flags&FIRST_INC_STRONG) ? true : false;
}

如果curCount <= 0(只会等于0),表示对象强引用数经历了INITIAL_STRONG_VALUE –>大于0 –> 0,接下来就要判断:

allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
    && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);

如果对象的生命周期受强引用数控制,那么由于曾被sp引用过,现在强引用数又为0,对象就已经被delete了,所以就不能生成强引用,否则如果对象的生命周期受弱引用数控制,就通过onIncStrongAttempted看类的实现者是否希望当对象的强引用数变为0时可以再次被强引用引用。

if (!allow) {
    decWeak(id);
    return false;
}

如果allow为false表示不能从弱引用生成强引用,就要调用decWeak将弱引用减1(因为在promote入口先将弱引用加了1),然后返回false表示生成强引用失败。

if (curCount == INITIAL_STRONG_VALUE) {
    android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
    impl->mBase->onFirstRef();
}

最后,如果curCount == INITIAL_STRONG_VALUE表示第一次被sp引用,调用对象的onFirstRef函数。

总结

RefBase内部有一个指针指向实际对象,有一个weakref_impl类型的指针保存对象的强/弱引用计数、对象生命周期控制。

sp只有一个成员变量,用来保存实际对象,但这个实际对象内部已包含了weakref_impl *对象用于保存实际对象的引用计数。sp 管理一个对象指针时,对象的强、弱引用数同时加1,sp销毁时,对象的强、弱引用数同时减1。

wp中有两个成员变量,一个保存实际对象,另一个是weakref_impl *对象。wp管理一个对象指针时,对象的弱引用计数加1,wp销毁时,对象的弱引用计数减1。

weakref_impl中包含一个flag用于决定对象的生命周期是由强引用数控制还是由弱引用数控制:

1.当flag为0时,实际对象的生命周期由强引用数控制,weakref_impl *对象由弱引用数控制。

2.当flag为OBJECT_LIFETIME_WEAK时,实际对象的生命周期受弱引用数控制。

3.当flag为OBJECT_LIFETIME_FOREVER时,实际对象的生命周期由用户控制。

可以用extendObjectLifetime改变flag的值。

最后

分享一份阿里十年技术专家联合打造的Android Framework学习指南。

由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要《Android Framework进阶学习指南》完整文档的可扫描下方卡片免费获取~

《Android Framework 开发揭秘》

目录

img

第一章 系统启动流程分析

​ ● 第一节 Android启动概览

​ ● 第二节 init.rc解析

​ ● 第三节 Zygote

​ ● 面试题

img

第二章 Binder解析

​ ● 第一节 宏观认识Binder

​ ● 第二节 binder的jni方法注册

​ ● 第三节 binder驱动

​ ● 第四节 数据结构

​ ● 第五节 启动service_manager

​ ● 第六节 获取service_manager

​ ● 第七节 addService流程

​ ● 第八节 Binder面试题全解析

第三章 Handler解析

​ ● 第一节 源码分析

​ ● 第二节 难点问题

​ ● 第三节 Handler常见面试题

第四章 AMS解析

​ ● 第一节 引言

​ ● 第二节 Android架构

​ ● 第三节 通信方式

​ ● 第四节 系统启动系列

​ ● 第五节 AMS

​ ● 第六节 AMS面试题解析

img

第五章 WMS解析

​ ● 第一节Activity与Window相关概念

​ ● 第二节 Android窗口管理服务WindowManagerService计算Activity窗口大

​ ● 第三节Android窗口管理服务WindowManagerService对窗口的组织方式分析

​ ● 第四节 Android窗口管理服务WindowManagerService对输入法窗口(Input

​ ● 第五节 Android窗口管理服务WindowManagerService对壁纸窗口(Wallpap

​ ● 第六节Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析

​ ● 第七节Android窗口管理服务WindowManagerService显示Activity组件的启

​ ● 第八节Android窗口管理服务WindowManagerService切换Activity窗口(A

​ ● 第九节 Android窗口管理服务WindowManagerService显示窗口动画的原理分析

img

Kylin操作系统下OpenLDAP安装 阅读详情

相关推荐

MATLAB实战:用ARMAX模型搞定电力系统惯量实时评估(附完整代码)

本文详细介绍了如何利用MATLAB中的ARMAX模型实现电力系统惯量的实时评估。通过系统辨识技术,结合电力系统的动态特性,提供从数据预处理、模型辨识到实时评估的全流程实战指南,并附完整代码。ARMAX模型在新能源高渗透率电网中展现出显著优势,误差较传统方法降低50%以上。

b9c0d的博客 394

Android 智能指针详解 -- RefBase

源码基于:Android N 相关博文:Android 智能指针详解Android 智能指针详解 -- wp Android 智能指针详解 -- spAndroid 智能指针详解 -- RefBase 关于android 智能指针,前面详细分析了sp 和 wp的source code,但是还有一些疑问,在这一篇中全部解释,因为所有的源头都是来自于这里。更多信息可以看 sp的博文 和 wp的博文source code:system/core/include/utils/RefBase.hsystem/core

私房菜 1万+

LCD、LED、OLED、Mini LED、Micro LED、全阵列LED、QLED、QD-OLED、QNED、AMOLED是什么意思?

LCD(液晶显示器,Liquid Crystal Display)定义:LCD 是一种利用液晶材料控制光线通过的显示技术,需依靠背光源(如冷阴极荧光灯 CCFL 或 LED)照亮液晶层以形成图像。技术原理:液晶分子在电场作用下改变排列,控制背光通过的强度和颜色。液晶本身不发光,需外部光源。特点:结构包括背光层、液晶层、彩色滤光片和偏光片。响应时间较慢,黑色表现因背光漏光而偏灰。LED(发光二极管显示,Light Emitting Diode)定义。

中国最威武的城市!武功军威-武威,铁骨铮铮! 3424

安卓系统智能指针:RefBase、sp、wp

在安卓中,RefBase结合sp(强指针)和wp(弱指针),实现了通过引用计数的方法来控制对象的生命周期的机制,解决对象的自动释放的问题。在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申 请的对象从而造成内存泄露(通过new生成的对象,需要调用delete才能释放内存);二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误(多个指针指向同一个对象,其中一个指针delete)。在使用RefBase后,动态申请的内存将会被自动释放(有点类似Java的垃圾回收),不需要再使用delete来

liweixin2018的博客 958

【笔记6】SP3485自动收发电路设计分析

则TXD路为1,MOS管导通,2/3引脚为0,芯片实际上事与愿违的进入了接收模式。但是,由于我们采用单根双绞线与上位机通信,在数据发出去前数据线上没有任何信号传输,所以AB处于高阻态,进而受到R1下拉与R2上拉的影响,差分信号为1,所以输出1;此外,RXD内路也被上拉,485总线B端上拉,A端下拉。此时TXD由于没有数据传输,所以一直处于1的状态,因而MOS管导通,2/3引脚为0,芯片处于正常接收状态。总而言之就是,RE#与 DE只能有一个是1,1代表微控制器向外发送,0代表微控制器接收。

Haytham233的博客 3138

微弱电流检测放大器PCB布线布局设计

微弱电流检测放大器PCB布线布局设计的注意事项,保护环的概念和相关设计。

ydgd118的博客 1万+

Android-深入理解常见类

文章目录深入理解常见类RefBase、sp和wp初识影子对象RefBase和它的影子sp上场sp析构的影响总结由弱生强总结破解生死魔咒延长生命的魔咒LIFETIME_WEAK的魔力LIFETIME_FOREVER 深入理解常见类 RefBase、sp和wp RefBase是Android中所有对象的始祖,RefBase结合sp和wp,实现了一套通过引用计数的方式来控制对象生命周期的机制,sp是strong pointer,wp是weak pointer。 初识影子对象 class A : public Re

李木子的博客 3524

别再用Excel画波特图了!用LTspice免费仿真软件,5分钟搞定电路传递函数分析

本文介绍了如何利用LTspice免费仿真软件高效绘制波特图,解决传统Excel绘图效率低、精度不足的问题。通过详细的操作步骤和实战案例,展示LTspice在电路传递函数分析中的自动化计算、专业级精度和完整特性展示等优势,帮助工程师快速完成频率响应分析。

weixin_42524226的博客 461

Android源码分析 理解Refbase

最近解决稳定性问题,遇到sp问题,本文就简单梳理RefBase和sp、wp下。

baiiu 943

接地设计的本质:按电流类型选择物理连接方式

接地是电子系统中实现电位参考、噪声抑制与安全保护的基础技术,其核心原理在于为不同性质的电流提供可控的低阻抗返回路径。从直流到GHz频段,电流的频率特性、能量等级和持续时间决定了接地的物理实现方式——工频安全电流依赖低电阻导体,高频噪声需低感平面或磁珠衰减,ESD脉冲要求受控泄放电阻,浪涌能量则必须通过独立短路径导入大地。这种‘目的决定方式’的设计逻辑,直接关联EMC合规性、信号完整性与系统可靠性。本文聚焦PCB级与设备级工程实践,详解安全地、功能地、浪涌地与静电地的判据差异及六种典型连接策略,帮助硬件工程师

weixin_36369848的博客 260

Unity基础篇-----Input输入

2、Input.GetTouch()方法,主要用于移动端开发使用,此方法主要获取触摸屏幕的操作数据,首先通过Input.touchCount这个方法获取到手指触摸屏幕的次数,通过GetTouch方法传输触摸次数,调用Touch结构判断手指的状态来是否为设定的状态,符合的话则执行相关内容。参数(“Horizontal”)表示左右的值,值为-1时,表示你在一直按下左方向对应的按键、设备类型为手柄时,表示你把推杆推到了最左边,为0时为默认位置,手柄中对应正中间,为1时与-1时对应的情况正好相反。

why820mmm的博客 3495

安卓智能指针sp、wp、RefBase浅析

安卓智能指针sp、wp、RefBase浅析

似霰的博客 1779

让 AI 自己“画施工图”——基于扩散模型的智能 CAD 管线生成

AI驱动CAD管线设计革命:Layout2CAD实现30秒自动化出图 针对设计院70%时间耗费在管线绘制的问题,研究团队基于Stable Diffusion开发了Layout2CAD系统,实现建筑草图到DWG施工图的智能转换。该系统采用三阶段流程:语义分割建筑底图→扩散生成多通道Heatmap(含管径/标高信息)→矢量化输出DWG实体,结合129M参数的多模块模型(Diffusion UNet+GraphRefiner)及规范判别器,确保1mm精度并自动满足GB50015-2019标准。

qq_74383080的博客 2014

Android framework RefBase,sp,wp

Android framework RefBase,sp,wp 的使用与源码分析

weixin_45767368的博客 1201

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Android Framework学习之RefBase,SP,WP解析

LightRefBase仅仅提供了引用计数的方法,具体引用数应该怎么管理,就要通过智能指针类来管理了,每当有一个智能指针指向对象时,对象的引用计数要加1,当一个智能指针取消指向对象时,对象的引用计数要减1,在C++中,当一个对象生成和销毁时会自动调用(拷贝)构造函数和析构函数,所以,对对象引用数的管理就可以放到智能指针的(拷贝)构造函数和析构函数中。sp 管理一个对象指针时,对象的强、弱引用数同时加1,sp销毁时,对象的强、弱引用数同时减1。

FeiPeng_的博客 1013

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Android framework回顾(2) sp 和 wp sp对象

sp wp T类直接关系,sp对象的理解

yefengxuelang的专栏 1851

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【Android FrameWork】第十三天:属于Andorid的C++智能指针

摘要:Android原生开发中,C/C++缺乏垃圾回收机制,手动内存管理易引发内存泄漏等问题。为此,Android提供了基于引用计数的智能指针体系:核心基类RefBase与封装类sp(强指针)、wp(弱指针)。RefBase维护强/弱引用计数,决定对象生命周期;sp通过自动增减强引用计数管理对象存活;wp仅增加弱引用计数,需通过lock()获取强指针访问对象。这套机制广泛应用于Framework和NDK开发,有效解决了内存泄漏、野指针和循环引用问题。

u012739527的博客 368

Android中的sp和wp指针

转载于: http://blog.youkuaiyun.com/droidphone/article/details/5799792 经常会在android的framework代码中发现sp和wp这样的指针,平时看的时候都把他当成一个普通的指针封装过掉了,这几天终于忍不住了,想深入了解一下。   相关的代码: frameworks/base/include/utils/Re

Sprd_MTK_Man 462

Android framework回想(2) sp 和 wp sp对象

用MediaPlayer说明sp的实现。sp是一个模板类,T是RefBase的子类。仅仅要继承于RefBase的类都能够使用sp。binder类也继承RefBase类,binder的实现离不开RefBase。 用例如以下代码说说我遇到的疑惑。 201 static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, ...

weixin_30807779的博客 100

[Android][Framework][智能指针]

智能指针简介 智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数,所以为了实现内存( 动态存储区) 的安全回收,必须对指针进行一层封装,而这个封装就是智能指针, c++的智能指针有很多实现方式,有auto_ptr , unique_ptr , shared_ptr 三种,还有其他的。 android 中的sp 句柄类实际上就是google 实现...

Hendy_Raw的博客 402

Android智能指针浅析

长久以来,C++中的内存管理问题一直让人头疼,空指针,野指针,内存泄露。。。。。。C++程序员看到这样的问题就是各种头大!这样的问题往往很难解决,尤其是代码架构比较庞大或者复杂的时候。但是同样是面向对象的JAVA语言却没有这个问题,为什么呢?因为java有GC,也就是垃圾回收而C++没有。C++的做法是:程序员必须做到在new一个对象之后当不需要使用它的时候必须delete这个对象。看来很好,没有问

Android Fans 5450

【Android FrameWork】延伸阅读:为什么Android不使用C++新特性的智能指针

Android选择自研RefBase智能指针而非采用C++11标准,主要基于三大原因:历史时间线错位、系统级定制需求和兼容性考量。Android核心架构设计早于C++11标准发布,早期只能自研解决方案。RefBase深度集成Binder跨进程通信机制,支持对象死亡通知等Android特有功能,且针对嵌入式设备进行了轻量级优化。此外,重构数十亿行核心代码和第三方硬件库的成本过高,使得Android保持RefBase体系,仅在新模块中有限采用C++11智能指针。这种折中方案平衡了系统稳定性和开发便利性。

u012739527的博客 337

Android 智能指针详解

来源: http://blog.youkuaiyun.com/shift_wwx/article/details/79045127 前言: android framework模块也持续工作了好多年,有些关键的东西还是需要总结,好记性不如烂笔头。最近在回顾C++11中的智能指针,想到了android 中的自带的智能指针,总结一下。 分三部分: 1、Android 智能指针详解 --

私房菜 1168

Android框架之Camera(2)HAL及so库的加载

HAL层作为纽带,把Framework层的APIs和底层驱动连接起来。简言之,上层需要什么操作接口,HAL层就负责实现之。

u013686019的专栏 3423

Android黑科技实现原理揭秘,被面试官问的Android-Framework难倒了

智能指针并不是固定的 “当强引用计数为 0 时,不论弱引用计数是否为 0 都销毁引用的对象” ,而是可以自定义规则。RefBase 提供了 extendObjectLifetime() 方法,可以用来设置引用计数器的规则,不同规则对删除目标对象的时机判断也是不一样的,包括以下三种规则:OBJECT_LIFETIME_STRONG:只有在这个对象内存空间中的强计数器值为 0 的时候才会销毁对象。

2401_84415203的博客 428
上一篇: 程序员求职焦虑怎么办?2023程序员该如何破局(预防篇)
下一篇: 程序员不是一个简简单单的职业
Agent学习路线
博客等级 码龄6年 1万+粉丝 1902原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值