android智能指针

2022-12-13

Android的C++部分代码中有大量的sp/wp存在,意思是strong pointer和weak pointer,看字面意思就是指针相关的东西。C++是通过new和delete进行内存的分配和释放的,但是有时候开发者会忘记使用delete导致内存泄露,所以Android中就创建了sp/wp等,用于避免内存泄露和提高开发效率。
强指针通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先通过wp所提供的promote()方法将弱指针升级为强指针。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。

sp

system\core\libutils\include\utils\StrongPointer.h
system\core\libutils\StrongPointer.cpp

template<typename T>
class sp {
public:
    inline sp() : m_ptr(nullptr) { }

    template <typename... Args>
    static inline sp<T> make(Args&&... args);

    static inline sp<T> fromExisting(T* other);
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
    sp(std::nullptr_t) : sp() {}
#else
    sp(T* other);  // NOLINT(implicit)
    template <typename U> sp(U* other);  // NOLINT(implicit)
                          sp& operator = (T* other);
    template <typename U> sp& operator = (U* other);
#endif

    sp(const sp<T>& other);
    sp(sp<T>&& other) noexcept;

    template<typename U> sp(const sp<U>& other);  // NOLINT(implicit)
    template<typename U> sp(sp<U>&& other);  // NOLINT(implicit)

    template <typename U>
    static inline sp<T> cast(const sp<U>& other);

    ~sp();

    sp& operator  = (const sp<T>& other);
    sp& operator  = (sp<T>&& other) noexcept;

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

    //! Special optimization for use by ProcessState (and nobody else).
    void force_set(T* other);

    void clear();

    inline T&       operator* () const     { return *m_ptr; }
    inline T*       operator-> () const    { return m_ptr;  }
    inline T*       get() const            { return m_ptr; }
    inline explicit operator bool () const { return m_ptr != nullptr; }

    // Punt these to the wp<> implementation.
    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return o == *this;
    }

    template<typename U>
    inline bool operator != (const wp<U>& o) const {
        return o != *this;
    }

private:
    template<typename Y> friend class sp;
    template<typename Y> friend class wp;
    void set_pointer(T* ptr);
    static inline void check_not_on_stack(const void* ptr);
    T* m_ptr;
};
  • sp是一个模板类
  • sp有7个构造函数
  • 有6个运算符=重载函数
  • m_ptr 是sp实际引用对象的指针变量,所有的操作都是通过这个变量来进行的。

sp构造函数

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other) {
        check_not_on_stack(other);
        other->incStrong(this);
    }
}
template <typename T>
template <typename U>
sp<T>::sp(U* other) : m_ptr(other) {
    if (other) {
        check_not_on_stack(other);
        (static_cast<T*>(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);
}
template <typename T>
sp<T>::sp(sp<T>&& other) noexcept : m_ptr(other.m_ptr) {
    other.m_ptr = nullptr;
}
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

重载运算符赋值

template <typename T>
sp<T>& sp<T>::operator=(T* other) {
    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
    if (other) {
        check_not_on_stack(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>
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) noexcept {
    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> 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;
}

make函数

template <typename T>
template <typename... Args>
sp<T> sp<T>::make(Args&&... args) {
    T* t = new T(std::forward<Args>(args)...);
    sp<T> result;
    result.m_ptr = t;
    t->incStrong(t);  // bypass check_not_on_stack for heap allocation
    return result;
}
  • sp实际就是一个引用,不会单独的申请内存,对引用对象的初始化是在make中
  • 初始化m_ptr指针
  • 引用计数加一

sp析构函数

template<typename T>
sp<T>::~sp() {
    if (m_ptr)
        m_ptr->decStrong(this);
}
  • 这里调用decStrong函数,把m_ptr的引用次数进行减一

RefBase

在前面的分析中我们看到了函数incStrong和decStrong,实际上这两个函数的实现都是在RefBase类中,然后所有需要用到智能指针的类都需要继承这个类。

class RefBase
{
public:
            void            incStrong(const void* id) const;
            void            incStrongRequireStrong(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                incWeakRequireWeak(const void* id);
        void                decWeak(const void* id);
        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id);

        bool                attemptIncWeak(const void* id);
        //! DEBUGGING ONLY: Get current weak ref count.
        int32_t             getWeakCount() const;
        void                printRefs() const;
        void                trackMe(bool enable, bool retain);
    };

            weakref_type*   createWeak(const void* id) const;
            weakref_type*   getWeakRefs() const;

    inline  void            printRefs() const { getWeakRefs()->printRefs(); }

    inline  void            trackMe(bool enable, bool retain)
    { 
        getWeakRefs()->trackMe(enable, retain); 
    }

protected:
                            RefBase();
    virtual                 ~RefBase();
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };
    
            void            extendObjectLifetime(int32_t mode);
            
    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;
};

RefBase构造函数

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

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;

    explicit weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE) //强引用计数 1<<28
        , mWeak(0) //弱引用计数
        , mBase(base)
        , mFlags(OBJECT_LIFETIME_STRONG) //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) { }
};
  • weakref_impl继承于RefBase的内部类weakref_type,但是除构造函数之外其他函数的实现都是空
  • weakref_impl的成员变量指针mBasesp<T>::make中new的对象
  • 个人感觉这个类目前没有啥用途,可能主要意图是google用于debug的吧

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);
    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);
}
  • 成员变量mStrongmWeak加1,因为mStrong初始化时设置成了1<<28,所以第一次调用的时候减去了1<<28。所以最终两个成员变量的值都表示当前被引用的次数
  • onFirstRef子类如果有需要其他的操作,可以重载这个函数进行实现。

decStrong

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

    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 {
            delete impl;
        }
    } else {
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase; //非强引用情况下释放
    }
}
  • 成员变量mStrongmWeak减1
  • 如果减1前,强引用是最后一个,mFlags强引用,就把对象释放,调用对应的析构函数
  • mFlags初始化时赋值OBJECT_LIFETIME_STRONG,目前没有其他地方更改这个值
  • 如果是非强引用的情况下,弱引用的次数为0,则释放对象,调用对应的析构函数

wp

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

    inline wp() : m_ptr(nullptr), m_refs(nullptr) { }

    static inline wp<T> fromExisting(T* other);

    // for more information about this flag, see above
#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
    wp(std::nullptr_t) : wp() {}
#else
    wp(T* other);  // NOLINT(implicit)
    template <typename U>
    wp(U* other);  // NOLINT(implicit)
    wp& operator=(T* other);
    template <typename U>
    wp& operator=(U* other);
#endif

    wp(const wp<T>& other);
    explicit wp(const sp<T>& other);
    template<typename U> wp(const sp<U>& other);  // NOLINT(implicit)
    template<typename U> wp(const wp<U>& other);  // NOLINT(implicit)

    ~wp();
    
    wp& operator = (const wp<T>& other);
    wp& operator = (const sp<T>& 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);

    sp<T> promote() const;
    void clear();

    inline  weakref_type* get_refs() const { return m_refs; }
    inline  T* unsafe_get() const { return m_ptr; }

    COMPARE_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK_FUNCTIONAL(>, std::greater)
    COMPARE_WEAK_FUNCTIONAL(<, std::less)
    COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal)
    COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal)

    template<typename U>
    inline bool operator == (const wp<U>& o) const {
        return m_refs == o.m_refs;
    }

    template<typename U>
    inline bool operator == (const sp<U>& o) const {
        if (o == nullptr) {
          return m_ptr == nullptr;
        } else {
          return m_refs == o->getWeakRefs();
        }
    }

    template<typename U>
    inline bool operator != (const sp<U>& o) const {
        return !(*this == o);
    }

    template<typename U>
    inline bool operator > (const wp<U>& o) const {
        if (m_ptr == o.m_ptr) {
            return _wp_compare_<std::greater>(m_refs, o.m_refs);
        } else {
            return _wp_compare_<std::greater>(m_ptr, o.m_ptr);
        }
    }

    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        if (m_ptr == o.m_ptr) {
            return _wp_compare_<std::less>(m_refs, o.m_refs);
        } else {
            return _wp_compare_<std::less>(m_ptr, o.m_ptr);
        }
    }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
    template<typename U> inline bool operator <= (const wp<U>& 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;
};
  • 大体上跟sp差不多,也有7个构造函数,6个=运算符重载
  • 增加了wp转换为sp的函数promote

promote

template<typename T>
sp<T> wp<T>::promote() const
{
    sp<T> result;
    if (m_ptr && m_refs->attemptIncStrong(&result)) {
        result.set_pointer(m_ptr);
    }
    return result;
}
template<typename T>
void sp<T>::set_pointer(T* ptr) {
    m_ptr = ptr;
}
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);

    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        //mStrong==curCount then mStrong=curCount+1 else curCount=mStrong
        if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                std::memory_order_relaxed)) {
            break;
        }
    }

    if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
        int32_t flags = impl->mFlags.load(std::memory_order_relaxed);
        if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
            if (curCount <= 0) {
                decWeak(id);
                return false;
            }
            while (curCount > 0) {
                if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
                        std::memory_order_relaxed)) {
                    break;
                }
            }
            if (curCount <= 0) {
                decWeak(id);
                return false;
            }
        } else {
            if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
                // it didn't so give-up.
                decWeak(id);
                return false;
            }
            curCount = impl->mStrong.fetch_add(1, std::memory_order_relaxed);
            if (curCount != 0 && curCount != INITIAL_STRONG_VALUE) {
                impl->mBase->onLastStrongRef(id);
            }
        }
    }

    impl->addStrongRef(id);
    if (curCount == INITIAL_STRONG_VALUE) {
        impl->mStrong.fetch_sub(INITIAL_STRONG_VALUE,
                std::memory_order_relaxed);
    }

    return true;
}

总结

  • 需要用智能指针的类都需要继承于RefBase
  • 通过sp<T>::make()进行实际对象的初始化,同时强弱引用计数加1
  • 强引用计数为0时,实际对象被释放
  • Flags为强引用时,弱引用计数为0时,weakref_impl被释放,否则实际对象被释放
  • 目前代码中常见的都是强引用
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容

  • [TOC]在Android系统中,Native层的代码基本都是C++写的,C++跟Java不一样,C++没有垃圾回...
    夕月风阅读 9,203评论 4 11
  • Android智能指针分析总结 什么是智能指针 C++ 指针需要手动释放,否则会造成内存泄露,但是如果项目工程比较...
    泡面先生_Jack阅读 693评论 1 1
  • 前言 Java 和 C/C++ 的一个重大区别,就是它没有"指针"的概念,这并不代表 Java 不需要只用指针,而...
    seraphzxz阅读 2,462评论 0 54
  • 本篇介绍 android中有三种智能指针,分别是轻量级指针,强指针,弱指针。轻量级指针实现简洁,效果类似于强指针,...
    android小奉先阅读 1,711评论 0 1
  • 引言:由于未来需要深入android底层进行系统级别的开发,所以最近在看老罗的《Android系统源代码情景分析》...
    拿破轮阅读 2,190评论 0 9