Android智能指針

前言

Java 和 C/C++ 的一個(gè)重大區(qū)別景埃,就是它沒(méi)有"指針"的概念普泡,這并不代表 Java 不需要只用指針您访,而是將這個(gè)"超級(jí)武器隱藏了"活逆。Java 以其他更"安全"的形式向開(kāi)發(fā)人員提供了隱形的"指針"精刷,使得用戶既能享受到指針的強(qiáng)大功能,又能盡量避免指針帶來(lái)的問(wèn)題蔗候。

C/C++中常見(jiàn)的指針問(wèn)題

  1. 指針沒(méi)有初始化

對(duì)指針進(jìn)行初始化是程序員必須養(yǎng)成的良好習(xí)慣怒允,也是指針問(wèn)題中最容易解決和控制的一個(gè)問(wèn)題;

  1. new 了對(duì)象沒(méi)有及時(shí) delete

動(dòng)態(tài)分配內(nèi)存的對(duì)象锈遥,其實(shí)聲明周期的控制不當(dāng)常常會(huì)引起不少麻煩纫事。如果只有一個(gè)程序員在維護(hù)時(shí),問(wèn)題通常不大所灸,因?yàn)橹灰晕⒘粜木涂梢詫?shí)現(xiàn) new 和 delete 的配套操作丽惶;但是如果一個(gè)大型工程,就很可能會(huì)出現(xiàn)動(dòng)態(tài)分配的內(nèi)存沒(méi)有回收的情況——造成的內(nèi)存泄露問(wèn)題往往是致命的爬立;

  1. 野指針
  • 假設(shè)1:我們 new 了一個(gè)對(duì)象 A钾唬,并將指針 ptr 指向這個(gè)新的對(duì)象。當(dāng)對(duì) A 使用結(jié)束后懦尝,我們也主動(dòng) delete 了 A知纷,但是唯一沒(méi)做的是將 ptr 指針置空,那么可能出現(xiàn)野指針問(wèn)題陵霉。因此如果有"第三方"視圖用 ptr 來(lái)使用內(nèi)存對(duì)象琅轧,它首先通過(guò)判斷發(fā)現(xiàn) ptr 不為空,就認(rèn)為這個(gè)對(duì)象還是存在的踊挠,其結(jié)果就是導(dǎo)致程序崩潰或是數(shù)據(jù)錯(cuò)誤乍桂;

  • 假設(shè)2:假設(shè) ptr1 和 ptr2 都指向?qū)ο?A冲杀,后來(lái)我們通過(guò) ptr1 釋放了 A 的內(nèi)存空間,并且將 ptr1 也置為 null睹酌;但是 ptr2 并不知道它所指向的內(nèi)存對(duì)象已經(jīng)不存在了权谁,此時(shí)如果 ptr2 來(lái)訪問(wèn) A 也會(huì)導(dǎo)錯(cuò)誤;

Android 智能指針

在開(kāi)發(fā)中經(jīng)常會(huì)使用對(duì)象引用計(jì)數(shù)來(lái)維護(hù)對(duì)象的生命周期憋沿,而該技術(shù)的核心問(wèn)題是由誰(shuí)來(lái)維護(hù)對(duì)象的引用計(jì)數(shù)旺芽,由開(kāi)發(fā)人員維護(hù)顯然既不可靠,又不方便編寫(xiě)和維護(hù)辐啄。而智能指針正是一種可以自動(dòng)維護(hù)對(duì)象引用計(jì)數(shù)的計(jì)數(shù)采章,需要注意的是,智能指針是一個(gè)對(duì)象壶辜,而不是一個(gè)指針悯舟。

現(xiàn)在考慮這樣一個(gè)問(wèn)題:

有兩個(gè)對(duì)象 A 和 B,A 引用了 B砸民,同時(shí) B 也引用了 A抵怎。當(dāng)對(duì)象 A 不再使用時(shí),就可以釋放它所占用的內(nèi)存岭参,但是由于 B 還持有 A 的引用反惕,結(jié)果就是 A 不能被釋放。對(duì)于釋放 B 的資源時(shí)也會(huì)遇到
同樣的問(wèn)題而不能得到釋放冗荸。這個(gè)問(wèn)題也是垃圾回收系統(tǒng)所遇到的經(jīng)典問(wèn)題之一承璃,因?yàn)樗淮沃荒苁占粋€(gè)對(duì)象占用的內(nèi)存(還要看的具體的回收機(jī)制)。

這就要使用一種特殊的智能指針技術(shù)蚌本,該技術(shù)將對(duì)象的引用計(jì)數(shù)分為強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)兩種盔粹,其中對(duì)象生命周期只受強(qiáng)引用計(jì)數(shù)控制。在使用以上引用計(jì)數(shù)方式時(shí)程癌,一般將有關(guān)聯(lián)的對(duì)象劃分為“父——子”和“子——父”關(guān)系舷嗡。“父”對(duì)象通過(guò)強(qiáng)引用來(lái)引用“子”對(duì)象嵌莉,“子”對(duì)象通過(guò)弱引用來(lái)引用“父”對(duì)象进萄。

以上面的 A 和 B 對(duì)象為例,假設(shè) A 和 B 是“父——子”關(guān)系锐峭,對(duì)象 A 通過(guò)強(qiáng)引用來(lái)引用 B中鼠,而 B 通過(guò)弱引用來(lái)引用 A。當(dāng)對(duì)象 A 不再使用的時(shí)沿癞,由于 B 使用過(guò)弱引用來(lái)引用 A 的援雇,而 對(duì)象的生命周期只受強(qiáng)引用計(jì)數(shù)控制,所以椎扬,A 的生命周期不受 B 的影響惫搏,可以安全釋放具温。在釋放 A 的同時(shí),也會(huì)釋放它對(duì) B 的強(qiáng)引用計(jì)數(shù)筐赔,因此 B 再不需要時(shí)可以被安全釋放铣猩。

由于對(duì)象生命周期只受強(qiáng)引用計(jì)數(shù)控制,因此在 B 想要使用 A 時(shí)茴丰,A 可能已經(jīng)被釋放了达皿,這個(gè)時(shí)候 B 不能直接使用 A 對(duì)象,而是先要成功的將對(duì)象 A 的弱引用計(jì)數(shù)升級(jí)為強(qiáng)引用計(jì)數(shù)贿肩,然后才能使用 A鳞绕;如果引用計(jì)數(shù)升級(jí)失敗,那么 B 就無(wú)法使用 A 了尸曼。

Android 系統(tǒng)設(shè)計(jì)了三種類(lèi)型的 C++ 智能指針,分別為:

  1. 輕量級(jí)指針:Light Pointer
  2. 強(qiáng)指針:Strong Pointer
  3. 弱指針:Weak set_pointer

其中輕量級(jí)指針使用了簡(jiǎn)單引用計(jì)數(shù)萄焦,而強(qiáng)指針和弱指針使用了強(qiáng)引用計(jì)數(shù)和引用計(jì)數(shù)控轿。

Android 提供了基類(lèi) RefBase,用以管理引用數(shù)拂封,所有支持使用強(qiáng)指針和弱指針的類(lèi)必須從 RefBase 派生茬射。設(shè)計(jì)模板類(lèi) sp、wp冒签,用以引用實(shí)際對(duì)象在抛,sp、wp 聲明為棧對(duì)象萧恕,作用域結(jié)束時(shí)刚梭,自動(dòng)釋放,自動(dòng)調(diào)用機(jī)析構(gòu)函數(shù)票唆。因此可以在 sp朴读、wp 的構(gòu)造函數(shù)中,增加引用計(jì)數(shù)走趋,在析構(gòu)函數(shù)中衅金,減少引用計(jì)數(shù)。專(zhuān)門(mén)設(shè)計(jì)的 weakref_impl 類(lèi)簿煌,該類(lèi)是 RefBase 的內(nèi)部類(lèi)氮唯,用來(lái)做真正的引用數(shù)管理,都由 mRef 來(lái)管理姨伟。

Android智能指針的關(guān)系圖:

Android智能指針的源碼位置

android中的智能指針的主要代碼是:RefBase.h惩琉、RefBase.cpp 以及 Pointer.h 這三個(gè)文件,他們分別位于:

RefBase.cpp: /system/core/libutils/RefBase.cpp
RefBase.h: /system/core/include/utils/RefBase.h
StrongPointer.h:/system/core/include/utils/StrongPointer.h

輕量級(jí)指針

這里不多提輕量級(jí)指針授滓,因?yàn)檫@種指針式通過(guò)簡(jiǎn)單引用計(jì)數(shù)技術(shù)來(lái)維護(hù)對(duì)象生命周期的琳水。關(guān)于它只需知道一下 3 點(diǎn):

  1. 第一點(diǎn)使用它需要繼承 LightRefBase(模板類(lèi))肆糕;

     public LightClass: public LightRefBase<LightClass>
    
  2. 第二點(diǎn) LightRefBase 類(lèi)只有一個(gè)成員變量 mCount 用來(lái)描述一個(gè)對(duì)象的引用計(jì)數(shù)值;

  3. 第三點(diǎn)需要知道輕量級(jí)指針的實(shí)現(xiàn)類(lèi)和強(qiáng)指針的實(shí)現(xiàn)類(lèi)是同一個(gè)類(lèi) sp在孝。

強(qiáng)指針和弱指針

強(qiáng)指針和弱指針通過(guò)強(qiáng)引用計(jì)數(shù)器和弱引用計(jì)數(shù)器來(lái)維護(hù)對(duì)象的生命周期诚啃。如果一個(gè)類(lèi)的對(duì)象要使用強(qiáng)指針和弱指針,那么就必須從 RefBase 類(lèi)繼承下來(lái)私沮,因?yàn)?RefBase 類(lèi)提供了強(qiáng)引用和弱引用計(jì)數(shù)器始赎。

強(qiáng)指針和弱指針關(guān)系比較密切,他們是配合在一起使用的仔燕。

強(qiáng)指針的實(shí)現(xiàn)原理分析

首先分析 RefBase 類(lèi)的實(shí)現(xiàn)原理造垛,源碼如下:

源碼位置:Android源碼目錄/system/core/include/utils/RefBase.h

class RefBase
{
public:
            void            incStrong(const void* id) const; // 增加強(qiáng)引用計(jì)數(shù)器的值
            void            decStrong(const void* id) const; // 減少?gòu)?qiáng)引用計(jì)數(shù)器的值

            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); //增加弱引用計(jì)數(shù)器的值
        void                decWeak(const void* id); //減少弱引用計(jì)數(shù)器的值

        // acquires a strong reference if there is already one.
        bool                attemptIncStrong(const void* id); //增加強(qiáng)引用計(jì)數(shù)器的值

        // 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); //減少?gòu)?qiáng)引用計(jì)數(shù)器的值

        //! 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(); // 構(gòu)造函數(shù)
    virtual                 ~RefBase(); // 析構(gòu)函數(shù)

    //! Flags for extendObjectLifetime()
    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,
        OBJECT_LIFETIME_WEAK    = 0x0001,
        OBJECT_LIFETIME_MASK    = 0x0001
    };

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

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; // 描述對(duì)象引用計(jì)數(shù)
};

RefBase 提供了成員函數(shù) incStrong 和 decStrong 來(lái)維護(hù)他所引用的對(duì)象的引用計(jì)數(shù),這是通過(guò)使用一個(gè) weakref_impl 對(duì)象晰搀,即成員變量 mRefs 來(lái)描述對(duì)象的引用計(jì)數(shù)五辽。

weakref_impl 同時(shí)為類(lèi)提供了強(qiáng)引用和弱引用計(jì)數(shù),源碼如下:

源碼位置:Android源碼目錄 /system/core/libutils/RefBase.cpp

class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
    std::atomic<int32_t>    mStrong; // 強(qiáng)引用計(jì)數(shù)
    std::atomic<int32_t>    mWeak; // 弱引用計(jì)數(shù)
    RefBase* const          mBase; // 引用對(duì)象的地址
    std::atomic<int32_t>    mFlags; // 描述生命周期控制方式

#if !DEBUG_REFS

    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
    ......
#endif
};

weakref_impl 繼承了 weakref_type 類(lèi)外恕,weakref_type 為 RefBase 內(nèi)部類(lèi)杆逗,它提供了成員函數(shù):incWeak、decWeak鳞疲、attemptIncStrong 和 attemptIncWeak 來(lái)維護(hù)對(duì)象的
強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)罪郊。weakref_type 只提供了方法接口,具體實(shí)現(xiàn)由 weakref_impl 完成尚洽。

weakref_impl 有兩個(gè)成員變量 mStrong 和 mWeak悔橄,分別描述對(duì)象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)。weakref_impl 的成員變量 mBase 指向了它所引用的對(duì)象的地址腺毫, 成員變量 mFlags 是一個(gè)標(biāo)志值癣疟,用來(lái)描述對(duì)象的生命周期的控制方式。mFlags 的去值范圍為:OBJECT_LIFETIME_STRONG潮酒、OBJECT_LIFETIME_WEAK 或是
OBJECT_LIFETIME_FOREVER争舞,其中 OBJECT_LIFETIME_STRONG 表示對(duì)象的生命周期只受到強(qiáng)引用計(jì)數(shù)的影響;OBJECT_LIFETIME_WEAK 表示對(duì)象的生命周期同時(shí)受到強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)的影響澈灼;OBJECT_LIFETIME_FOREVER 表示完全不受強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)的影響竞川。

以上三個(gè)類(lèi)關(guān)系如下:

RefBase_reference_01.png

強(qiáng)指針實(shí)現(xiàn)類(lèi) sp

強(qiáng)指針的實(shí)現(xiàn)類(lèi)為 sp,下面主要分析它的構(gòu)造蛤蟆數(shù)和析構(gòu)函數(shù)叁熔。

sp 源碼如下:

源碼位置:Android源碼目錄/system/core/include/utils/StrongPointer.h

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

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

    ~sp();

    // Assignment

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

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

sp 構(gòu)造函數(shù)

sp 的構(gòu)造函數(shù)如下:

源碼位置:Android源碼目錄/system/core/include/utils/StrongPointer.h

template<typename T>
sp<T>::sp(T* other)
        : m_ptr(other) {
    if (other)
        other->incStrong(this);
}

模塊參數(shù) T 繼承了 RefBase 類(lèi)的子類(lèi)委乌,因此,以上代碼實(shí)際上會(huì)調(diào)用 RefBase 的成員函數(shù) incStrong 來(lái)增加對(duì)象的強(qiáng)引用計(jì)數(shù)荣回,如下所示:

源碼位置:Android源碼目錄/system/core/libutils/RefBase.cp

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;
    refs->incWeak(id); // 增加對(duì)象的弱引用計(jì)數(shù)

    refs->addStrongRef(id);
    // 增加對(duì)象的強(qiáng)引用計(jì)數(shù)
    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 = 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);
    // 來(lái)通知對(duì)象它被強(qiáng)指針引用了
    refs->mBase->onFirstRef();
}

RefBase 的成員變量 mRefs 是在構(gòu)造函數(shù)中初始化的遭贸,如下所示:

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

接著分析 RefBase 的 incStrong 函數(shù),它主要做了三件事:

  1. 增加對(duì)象的弱引用計(jì)數(shù)心软;
  2. 增加對(duì)象的強(qiáng)引用計(jì)數(shù)壕吹;
  3. 如果對(duì)象是第一次被強(qiáng)指針引用著蛙,調(diào)用成員函數(shù) onFirstRef 來(lái)通知對(duì)象,它被強(qiáng)指針引用了耳贬,以便可以執(zhí)行一些業(yè)務(wù)邏輯踏堡。

增加對(duì)象弱引用計(jì)數(shù)是通過(guò)調(diào)用 RefBase 的成員變量 mRefs(也就是 weakref_impl)的成員函數(shù) incWeak 來(lái)實(shí)現(xiàn)的,它是 weakref_type 的子類(lèi)咒劲,函數(shù) incWeak 是從其父類(lèi)繼承下來(lái)的顷蟆,
weakref_type 中 incWeak 代碼如下:

void RefBase::weakref_type::incWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->addWeakRef(id); // 調(diào)試相關(guān),忽略
    const int32_t c __unused = impl->mWeak.fetch_add(1,
            std::memory_order_relaxed); // 增加弱引用計(jì)數(shù)
    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}

這里 this 指針實(shí)際上是指向一個(gè) weakref_impl 對(duì)象腐魂,因此將其轉(zhuǎn)化為 weakref_impl 指針帐偎,接下來(lái)增加它的成員變量 mWeak 的值,即增加對(duì)象的弱引用計(jì)數(shù)蛔屹。

增加了對(duì)向的弱引用后削樊,接著就增加對(duì)象的強(qiáng)引用計(jì)數(shù),也就是增加 mRefs 的成員變量 mStrong 的值兔毒。并返回對(duì)象原來(lái)的強(qiáng)引用計(jì)數(shù)值嫉父,即加一前的值。在 weakref_impl 的構(gòu)造函數(shù)中眼刃,成員
變量 mStrong 的值被初始化為 INITIAL_STRONG_VALUE。INITIAL_STRONG_VALUE 是一個(gè)宏摇肌,其定義如下:

#define INITIAL_STRONG_VALUE (1<<28)

理論上擂红,對(duì)象第一次被強(qiáng)指針引用時(shí),它的強(qiáng)引用計(jì)數(shù)應(yīng)該為 1围小,但是 INITIAL_STRONG_VALUE + 1 的值并不等于 1昵骤,因此,RefBase 類(lèi)的成員函數(shù) incStrong 就需要將它的值調(diào)整為 1 這
是通過(guò)

int32_t old = refs->mStrong.fetch_sub(INITIAL_STRONG_VALUE,std::memory_order_relaxed);

實(shí)現(xiàn)的肯适。

至此 sp 的構(gòu)造函數(shù)分析完了变秦,它主要做的事就是增加強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)。

下分析 sp 的析構(gòu)函數(shù)框舔。

sp 析構(gòu)函數(shù)

析構(gòu)函數(shù)代碼如下:

源碼位置:Android源碼目錄/system/core/include/utils/StrongPointer.h

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

m_ptr 所指向的對(duì)象是繼承了 RefBase 的類(lèi)蹦玫,所以這里實(shí)際上調(diào)用了 RefBase 的 decStrong 函數(shù)來(lái)減少對(duì)象的強(qiáng)引用計(jì)數(shù),其實(shí)現(xiàn)如下:

源碼位置:Android源碼目錄/system/core/libutils/RefBase.cpp

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
    ALOG_ASSERT(c >= 1, "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);
}

sp 析構(gòu)函數(shù)的主要工作就是減少對(duì)象強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)刘绣。與其構(gòu)造函數(shù)一樣

const int32_t c = refs->mStrong.fetch_sub(1, std::memory_order_release);

也是返回原來(lái)的強(qiáng)引用計(jì)數(shù)樱溉,即減1前的值,并保存在了變量 c 中纬凤。如果變量 c 的值等于1福贞,也就是說(shuō),此時(shí)沒(méi)有強(qiáng)指針引用這個(gè)對(duì)象了停士,接下來(lái)就可以調(diào)用

refs->mBase->onLastStrongRef(id);

來(lái)執(zhí)行一些業(yè)務(wù)相關(guān)邏輯挖帘,同時(shí)也需要考慮是否需要釋放該對(duì)象完丽。接下來(lái)判斷對(duì)象的生命周期是否只受強(qiáng)引用控制,如果是拇舀,那么就下來(lái)就會(huì)釋放對(duì)象所占用的內(nèi)存逻族,同時(shí)導(dǎo)致 RefBase 的
析構(gòu)函數(shù)被調(diào)用,代碼如下:

源碼位置:Android源碼目錄/system/core/libutils/RefBase.cpp

RefBase::~RefBase()
{
    if (mRefs->mStrong.load(std::memory_order_relaxed)
            == INITIAL_STRONG_VALUE) {
        delete mRefs;
    } else {
        int32_t flags = mRefs->mFlags.load(std::memory_order_relaxed);
        // 生命周期不只是受強(qiáng)引用計(jì)數(shù)控制
        if ((flags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
            if (mRefs->mWeak.load(std::memory_order_relaxed) == 0) {
                delete mRefs;
            }
        }
    }
    // 只受強(qiáng)引用計(jì)數(shù)控制你稚,只釋放 RefBase瓷耙,保留 mRefs
    const_cast<weakref_impl*&>(mRefs) = NULL;
}

如果強(qiáng)引用計(jì)數(shù)為初始值,也就是說(shuō)該對(duì)象沒(méi)有被強(qiáng)指針引用過(guò)刁赖,那么釋放成員變量 mRefs(weakref_impl)搁痛;當(dāng)強(qiáng)引用計(jì)數(shù)為 0,但是弱引用不為 0時(shí)宇弛,只能將對(duì)象 RefBase 釋放掉鸡典,而不能將 weakref_impl
對(duì)象 mRefs 釋放掉,因?yàn)檫€有其他的弱指針通過(guò)該 weakref_impl 對(duì)象來(lái)引用實(shí)際對(duì)象枪芒。只有對(duì)象的弱引用計(jì)數(shù)為 0 時(shí)彻况,才可以將 weakref_impl 一起釋放掉。

回到函數(shù) decStrong 中舅踪,接下來(lái)通過(guò)

refs->decWeak(id);

減少弱引用計(jì)數(shù)纽甘。refs 是 weakref_impl 對(duì)象,weakref_impl繼承自 weakref_type抽碌,這里實(shí)際會(huì)調(diào)用 weakref_type 的 decWeak 函數(shù)悍赢,代碼如下:

void RefBase::weakref_type::decWeak(const void* id)
{
    weakref_impl* const impl = static_cast<weakref_impl*>(this);
    impl->removeWeakRef(id);
    // 減少弱引用計(jì)數(shù)
    const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release);
    ALOG_ASSERT(c >= 1, "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(std::memory_order_relaxed);
    if ((flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
        if (impl->mStrong.load(std::memory_order_relaxed)
                == INITIAL_STRONG_VALUE) {
            // Special case: we never had a strong reference, so we need to
            // destroy the object now.
            delete impl->mBase;
        } else {
            // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
            delete impl;
        }
    } else {
        impl->mBase->onLastWeakRef(id);
        delete impl->mBase;
    }
}

函數(shù)

impl->mWeak.fetch_sub(1, std::memory_order_release);

會(huì)返回對(duì)象的原弱引用計(jì)數(shù),即減1前的值货徙,并存放在變量 c 中左权,如果 c 不為 1,也就是說(shuō)還有其他弱指針指向該對(duì)象痴颊,因此就不做進(jìn)一步處理赏迟;如果 c 的值等于 1,也就是說(shuō)沒(méi)有其他弱指針指引用
該對(duì)象了蠢棱,同時(shí)也說(shuō)明沒(méi)有強(qiáng)指針引用該對(duì)象了锌杀,這是需要考慮是否釋放掉該對(duì)象。這取決于對(duì)象生命周期的控制方式泻仙,以及該對(duì)象是否被強(qiáng)指針引用過(guò)抛丽。下面分兩種情況討論。

  1. 對(duì)象生命周期只受強(qiáng)引用計(jì)數(shù)控制饰豺,即 (flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG 為 true亿鲜,如果此時(shí) impl->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE 也為 true,也就是說(shuō)該對(duì)象沒(méi)有被強(qiáng)指針引用過(guò),那么就可以將該對(duì)象釋放掉蒿柳。如果對(duì)象的生命周期只受強(qiáng)引用計(jì)數(shù)控制饶套,并且也被強(qiáng)指針引用過(guò),那么在該對(duì)象的弱引用計(jì)數(shù)變?yōu)?0 時(shí)垒探,該對(duì)象就已經(jīng)在 RefBase 的成員函數(shù) decStrong 中被釋放掉了妓蛮,因此,接下來(lái)就只釋放其內(nèi)部的引用計(jì)數(shù)器對(duì)象 weakref_impl圾叼。

  2. 生命周期受弱引用控制蛤克,,那么接下來(lái)就可以調(diào)用 onLastWeakRef 來(lái)處理一些業(yè)務(wù)相關(guān)邏輯夷蚊,接著將將該對(duì)象釋放掉构挤。

總結(jié)

  • 如果一個(gè)對(duì)象的生命周期只受到強(qiáng)引用控制,那么只要它的強(qiáng)引用計(jì)數(shù)值為 0惕鼓,系統(tǒng)就會(huì)釋放掉該對(duì)象;
  • 如果一個(gè)對(duì)象的生命周期控制標(biāo)志被設(shè)置為 OBJECT_LIFETIME_WEAK筋现,只有當(dāng)強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)都是 0時(shí),系統(tǒng)才會(huì)釋放掉這個(gè)對(duì)象箱歧。

弱指針的實(shí)現(xiàn)原理分析

wp 類(lèi)的定義如下矾飞;

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_WEAK(==)
    COMPARE_WEAK(!=)
    COMPARE_WEAK(>)
    COMPARE_WEAK(<)
    COMPARE_WEAK(<=)
    COMPARE_WEAK(>=)

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

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

    inline bool operator < (const wp<T>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
    template<typename U>
    inline bool operator < (const wp<U>& o) const {
        return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
    }
                         inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
    template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
                         inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
    template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
                         inline bool operator >= (const wp<T>& 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;

    // 指向他所引用的對(duì)象(繼承自 RefBase)
    T*              m_ptr;
    // 用來(lái)維護(hù)對(duì)象的弱引用計(jì)數(shù)
    weakref_type*   m_refs;
};

需要注意的是,弱指針與強(qiáng)指針有一個(gè)很大的區(qū)別呀邢,就是弱指針不可以直接操作他所引用的對(duì)象洒沦,因?yàn)樗玫膶?duì)象可能不受弱引用計(jì)數(shù)的控制,即它所引用的對(duì)象可能是一個(gè)無(wú)效的對(duì)象价淌。因此如果需要操作一個(gè)弱指針引用的對(duì)象申眼,那么就需要將這個(gè)弱指針升級(jí)為強(qiáng)指針,這是通過(guò)它的成員函數(shù) promote 實(shí)現(xiàn)的输钩。如果升級(jí)成功,那么就說(shuō)明該弱指針?biāo)玫膶?duì)象還沒(méi)有被銷(xiāo)毀仲智,可以正常使用买乃。

wp 的實(shí)現(xiàn)比較復(fù)雜,重點(diǎn)是理解它的構(gòu)造函數(shù)钓辆、析構(gòu)函數(shù)意以及如何將一個(gè)弱指針升級(jí)為一個(gè)強(qiáng)指針剪验。

首先分析它的構(gòu)造函數(shù)。

wp 構(gòu)造函數(shù)

源碼位置:Android源碼目錄/system/core/include/utils/RefBase.h

template<typename T>
wp<T>::wp(T* other)
    : m_ptr(other)
{
    if (other) m_refs = other->createWeak(this);
}

實(shí)際上是調(diào)用 RefBase 的成員函數(shù) createWeak 來(lái)增加對(duì)象的弱引用計(jì)數(shù)前联,代碼如下:

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

RefBase 的成員變量 mRefs 指向 weakref_impl 對(duì)象功戚,它的成員方法 incWeak 就是增加實(shí)際引用對(duì)象的弱引用計(jì)數(shù),最后將 mRefs 返回似嗤。

wp 析構(gòu)函數(shù)

源碼位置:Android源碼目錄/system/core/include/utils/RefBase.h

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

就是調(diào)用 它的成員變量 m_refs 的成員函數(shù) decWeak 來(lái)減少弱引用計(jì)數(shù)啸臀。m_refs指向的是一個(gè) weakref_impl 對(duì)象,因此這里實(shí)際上會(huì)調(diào)用 weakref_impl 的成員函數(shù) decWeak 來(lái)減少對(duì)象的弱引用計(jì)數(shù)。

接下來(lái)重點(diǎn)分析 wp 的成員函數(shù) promote乘粒,該函數(shù)用來(lái)將一個(gè)弱指針升級(jí)為一個(gè)強(qiáng)指針豌注。前面介紹到弱引用不能直接操作它引用的對(duì)象,那么這是如何實(shí)現(xiàn)的呢灯萍?

  • wp 沒(méi)有重載 “*” 和 “->”操作符轧铁,因此,我們就不能直接操作它所引用的對(duì)象旦棉。

wp 的成員函數(shù) promote 實(shí)現(xiàn)如下:

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

m_ptr 指向?qū)ο蟮牡刂烦莘纾琺_refs 指向該對(duì)象內(nèi)部的一個(gè)弱引用計(jì)數(shù)器。只有在對(duì)象地址不為NULL的情況下绑洛,才會(huì)調(diào)用它內(nèi)部的弱引用計(jì)數(shù)器對(duì)象的成員函數(shù) attemptIncStrong 來(lái)試圖增加該對(duì)象的強(qiáng)引用計(jì)數(shù)救斑。如果能夠成功增加強(qiáng)引用計(jì)數(shù),那么就可以成功地把一個(gè)弱指針升級(jí)為一個(gè)強(qiáng)指針诊笤。m_refs是一個(gè)類(lèi)型為 weakref_type 的指針系谐,因此接下來(lái)就會(huì)調(diào)用 weakref_type 的成員函數(shù)attemptIncStrong,其實(shí)現(xiàn)如下:

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

    while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
        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)) {
                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 PRINT_REFS
    ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
#endif

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

    return true;
}

weakref_type 的成員函數(shù) attemptIncStrong 試圖增加目標(biāo)對(duì)象的強(qiáng)引用計(jì)數(shù)器讨跟,但是可能會(huì)增加失敿退(目標(biāo)對(duì)象已經(jīng)被釋放,或者該目標(biāo)對(duì)象不允許使用強(qiáng)指針引用它)晾匠。

在增加強(qiáng)引用計(jì)數(shù)的同時(shí)也會(huì)增加弱引用計(jì)數(shù)茶袒,因此以上函數(shù)首先調(diào)用 incWeak 來(lái)增加弱引用計(jì)數(shù)。wp 的成員變量 m_refs 指向的是一個(gè) weakref_impl 對(duì)象凉馆,接下來(lái)可以安全地將 this 指針
轉(zhuǎn)化為 weakref_impl 指針薪寓,并保存在 impl 中。

一個(gè)弱指針引用的對(duì)象可能處于兩種狀態(tài):

  1. 該對(duì)象正被其他強(qiáng)指針引用澜共,因此它的強(qiáng)引用計(jì)數(shù)值大于 0向叉,并且不等于 INITIAL_STRONG_VALUE;
  2. 該對(duì)象沒(méi)用被任何強(qiáng)者針引用嗦董,即它的強(qiáng)引用計(jì)數(shù)值小于等于 0母谎,或是等于 INITIAL_STRONG_VALUE。

先分析第一種情形京革,由于它的強(qiáng)引用計(jì)數(shù)值大于 0奇唤,也就是說(shuō)這時(shí)候?qū)ο笠欢ㄊ谴嬖诘模虼丝梢园踩膶⑷踔羔樕?jí)為強(qiáng)指針匹摇,并將對(duì)象的強(qiáng)引用計(jì)數(shù)加 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.
    if (impl->mStrong.compare_exchange_weak(curCount, curCount+1,
            std::memory_order_relaxed)) {
        break;
    }
}

compare_exchange_weak 可以保證原子性,也會(huì)出現(xiàn)增加強(qiáng)引用計(jì)數(shù)失敗的情況廊勃,在調(diào)用函數(shù) compare_exchange_weak 前懈贺,其他線程正在修改 curCount 的值就會(huì)造成這種情況,通過(guò) while 循環(huán)來(lái)重新執(zhí)行該操作。

第二種情況比較復(fù)雜隅居,此時(shí)對(duì)象可能存在也可能不存在钠至,要進(jìn)一步判斷。

  1. 如果 (flags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG 為 true胎源,也就是說(shuō)該對(duì)象生命周期只受強(qiáng)引用計(jì)數(shù)控制棉钧。

    • 如果 curCount <= 0 也就是說(shuō)該對(duì)象不存在,那么減少之前增加的弱引用計(jì)數(shù)涕蚤,并返回 false宪卿;
    • 如果 curCount > 0,實(shí)際上就是 curCount == INITIAL_STRONG_VALUE万栅,此時(shí)由于該對(duì)象生命周期只受強(qiáng)引用計(jì)數(shù)控制佑钾,而此時(shí)該對(duì)象又沒(méi)有被任何強(qiáng)指針引用過(guò),那么它必然不會(huì)被釋放烦粒,此時(shí)可以安全的將其升級(jí)為強(qiáng)指針休溶。
  2. 如果該對(duì)象的生命周期受弱引用計(jì)數(shù)影響,那么就說(shuō)明該對(duì)象肯定是存在的扰她,因?yàn)楝F(xiàn)在正有一個(gè)弱指針在引用該對(duì)象兽掰。但是還要進(jìn)一步調(diào)用函數(shù) onIncStrongAttempted 來(lái)確認(rèn)對(duì)象是否允許強(qiáng)指針引用它。如果為 true徒役,那么就可以成功升級(jí)為強(qiáng)指針孽尽。

onIncStrongAttempted 實(shí)現(xiàn)如下:

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

RefBase 類(lèi)的成員函數(shù)在參數(shù) flags 為 FIRST_INC_STRONG 的情況下允許將一個(gè)指向只受弱引用計(jì)數(shù)影響生命周期的對(duì)象的弱指針升級(jí)為強(qiáng)指針。

到這里關(guān)于只能指針的相關(guān)內(nèi)容的分析就基本完成了忧勿,希望對(duì)你有幫助杉女。

參考文獻(xiàn):

Android 系統(tǒng)源代碼情景分析

Android系統(tǒng)的智能指針(輕量級(jí)指針横腿、強(qiáng)指針和弱指針)的實(shí)現(xiàn)原理分析

Android跨進(jìn)程通信IPC之4——AndroidIPC基礎(chǔ)2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诀紊,一起剝皮案震驚了整個(gè)濱河市窑邦,隨后出現(xiàn)的幾起案子唆垃,更是在濱河造成了極大的恐慌,老刑警劉巖瓶逃,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啄糙,死亡現(xiàn)場(chǎng)離奇詭異际度,居然都是意外死亡贡羔,警方通過(guò)查閱死者的電腦和手機(jī)廉白,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)个初,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乖寒,“玉大人,你說(shuō)我怎么就攤上這事院溺¢灌遥” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)逐虚。 經(jīng)常有香客問(wèn)我聋溜,道長(zhǎng),這世上最難降的妖魔是什么叭爱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任撮躁,我火速辦了婚禮,結(jié)果婚禮上买雾,老公的妹妹穿的比我還像新娘把曼。我一直安慰自己,他們只是感情好漓穿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布嗤军。 她就那樣靜靜地躺著,像睡著了一般晃危。 火紅的嫁衣襯著肌膚如雪叙赚。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天僚饭,我揣著相機(jī)與錄音震叮,去河邊找鬼。 笑死浪慌,一個(gè)胖子當(dāng)著我的面吹牛冤荆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播权纤,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钓简,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了汹想?” 一聲冷哼從身側(cè)響起外邓,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎古掏,沒(méi)想到半個(gè)月后损话,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡槽唾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年丧枪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庞萍。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拧烦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钝计,到底是詐尸還是另有隱情恋博,我是刑警寧澤齐佳,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站债沮,受9級(jí)特大地震影響炼吴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疫衩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一硅蹦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闷煤,春花似錦提针、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至皆愉,卻和暖如春嗜价,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背幕庐。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工久锥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人异剥。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓瑟由,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親冤寿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歹苦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355