日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】...

發(fā)布時(shí)間:2023/12/10 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android系統(tǒng)的運(yùn)行時(shí)庫層代碼是用C++來編寫的,用C++ 來寫代碼最容易出錯(cuò)的地方就是指針了,一旦使用不當(dāng),輕則造成內(nèi)存泄漏,重則造成系統(tǒng)崩潰。不過系統(tǒng)為我們提供了智能指針,避免出現(xiàn)上述問題,本文將系統(tǒng)地分析Android系統(tǒng)智能指針(輕量級指針、強(qiáng)指針和弱指針)的實(shí)現(xiàn)原理。

在使用C++來編寫代碼的過程中,指針使用不當(dāng)造成內(nèi)存泄漏一般就是因?yàn)閚ew了一個(gè)對象并且使用完之后,忘記了delete這個(gè)對象,而造成系統(tǒng)崩潰一般就是因?yàn)橐粋€(gè)地方delete了這個(gè)對象之后,其它地方還在繼續(xù)使原來指向這個(gè)對象的指針。

為了避免出現(xiàn)上述問題,一般的做法就是使用引用計(jì)數(shù)的方法,每當(dāng)有一個(gè)指針指向了一個(gè)new出來的對象時(shí),就對這個(gè)對象的引用計(jì)數(shù)增加1,每當(dāng)有一個(gè)指針不再使用這個(gè)對象時(shí),就對這個(gè)對象的引用計(jì)數(shù)減少1,每次減1之后,如果發(fā)現(xiàn)引用計(jì)數(shù)值為0時(shí),那么,就要delete這個(gè)對象了,這樣就避免了忘記delete對象或者這個(gè)對象被delete之后其它地方還在使用的問題了。

但是,如何實(shí)現(xiàn)這個(gè)對象的引用計(jì)數(shù)呢?肯定不是由開發(fā)人員來手動(dòng)地維護(hù)了,要開發(fā)人員時(shí)刻記住什么時(shí)候該對這個(gè)對象的引用計(jì)數(shù)加1,什么時(shí)候該對這個(gè)對象的引用計(jì)數(shù)減1,一來是不方便開發(fā),二來是不可靠,一不小心哪里多加了一個(gè)1或者多減了一個(gè)1,就會(huì)造成災(zāi)難性的后果。這時(shí)候,智能指針就粉墨登場了。首先,智能指針是一個(gè)對象,不過這個(gè)對象代表的是另外一個(gè)真實(shí)使用的對象,當(dāng)智能指針指向?qū)嶋H對象的時(shí)候,就是智能指針對象創(chuàng)建的時(shí)候,當(dāng)智能指針不再指向?qū)嶋H對象的時(shí)候,就是智能指針對象銷毀的時(shí)候,我們知道,在C++中,對象的創(chuàng)建和銷毀時(shí)會(huì)分別自動(dòng)地調(diào)用對象的構(gòu)造函數(shù)和析構(gòu)函數(shù),這樣,負(fù)責(zé)對真實(shí)對象的引用計(jì)數(shù)加1和減1的工作就落實(shí)到智能指針對象的構(gòu)造函數(shù)和析構(gòu)函數(shù)的身上了,這也是為什么稱這個(gè)指針對象為智能指針的原因。

在計(jì)算機(jī)科學(xué)領(lǐng)域中,提供垃圾收集(Garbage Collection)功能的系統(tǒng)框架,即提供對象托管功能的系統(tǒng)框架,例如Java應(yīng)用程序框架,也是采用上述的引用計(jì)數(shù)技術(shù)方案來實(shí)現(xiàn)的,然而,簡單的引用計(jì)數(shù)技術(shù)不能處理系統(tǒng)中對象間循環(huán)引用的情況。考慮這樣的一個(gè)場景,系統(tǒng)中有兩個(gè)對象A和B,在對象A的內(nèi)部引用了對象B,而在對象B的內(nèi)部也引用了對象A。當(dāng)兩個(gè)對象A和B都不再使用時(shí),垃圾收集系統(tǒng)會(huì)發(fā)現(xiàn)無法回收這兩個(gè)對象的所占據(jù)的內(nèi)存的,因?yàn)橄到y(tǒng)一次只能收集一個(gè)對象,而無論系統(tǒng)決定要收回對象A還是要收回對象B時(shí),都會(huì)發(fā)現(xiàn)這個(gè)對象被其它的對象所引用,因而就都回收不了,這樣就造成了內(nèi)存泄漏。這樣,就要采取另外的一種引用計(jì)數(shù)技術(shù)了,即對象的引用計(jì)數(shù)同時(shí)存在強(qiáng)引用和弱引用兩種計(jì)數(shù),例如,Apple公司提出的Cocoa框架,當(dāng)父對象要引用子對象時(shí),就對子對象使用強(qiáng)引用計(jì)數(shù)技術(shù),而當(dāng)子對象要引用父對象時(shí),就對父對象使用弱引用計(jì)數(shù)技術(shù),而當(dāng)垃圾收集系統(tǒng)執(zhí)行對象回收工作時(shí),只要發(fā)現(xiàn)對象的強(qiáng)引用計(jì)數(shù)為0,而不管它的弱引用計(jì)數(shù)是否為0,都可以回收這個(gè)對象,但是,如果我們只對一個(gè)對象持有弱引用計(jì)數(shù),當(dāng)我們要使用這個(gè)對象時(shí),就不直接使用了,必須要把這個(gè)弱引用升級成為強(qiáng)引用時(shí),才能使用這個(gè)對象,在轉(zhuǎn)換的過程中,如果對象已經(jīng)不存在,那么轉(zhuǎn)換就失敗了,這時(shí)候就說明這個(gè)對象已經(jīng)被銷毀了,不能再使用了。

了解了這些背景知識后,我們就可以進(jìn)一步學(xué)習(xí)Android系統(tǒng)的智能指針的實(shí)現(xiàn)原理了。Android系統(tǒng)提供了強(qiáng)大的智能指針技術(shù)供我們使用,這些智能指針實(shí)現(xiàn)方案既包括簡單的引用計(jì)數(shù)技術(shù),也包括了復(fù)雜的引用計(jì)數(shù)技術(shù),即對象既有強(qiáng)引用計(jì)數(shù),也有弱引用計(jì)數(shù),對應(yīng)地,這三種智能指針分別就稱為輕量級指針(Light Pointer)、強(qiáng)指針(Strong Pointer)和弱指針(Weak Pointer)。無論是輕量級指針,還是強(qiáng)指針和弱指針,它們的實(shí)現(xiàn)框架都是一致的,即由對象本身來提供引用計(jì)數(shù)器,但是它不會(huì)去維護(hù)這個(gè)引用計(jì)數(shù)器的值,而是由智能指針來維護(hù),就好比是對象提供素材,但是具體怎么去使用這些素材,就交給智能指針來處理了。由于不管是什么類型的對象,它都需要提供引用計(jì)數(shù)器這個(gè)素材,在C++中,我們就可以把這個(gè)引用計(jì)數(shù)器素材定義為一個(gè)公共類,這個(gè)類只有一個(gè)成員變量,那就是引用計(jì)數(shù)成員變量,其它提供智能指針引用的對象,都必須從這個(gè)公共類繼承下來,這樣,這些不同的對象就天然地提供了引用計(jì)數(shù)器給智能指針使用了。總的來說就是我們在實(shí)現(xiàn)智能指會(huì)的過程中,第一是要定義一個(gè)負(fù)責(zé)提供引用計(jì)數(shù)器的公共類,第二是我們要實(shí)現(xiàn)相應(yīng)的智能指針對象類,后面我們會(huì)看到這種方案是怎么樣實(shí)現(xiàn)的。

接下來,我們就先介紹輕量級指針的實(shí)現(xiàn)原理,然后再接著介紹強(qiáng)指針和弱指針的實(shí)現(xiàn)原理。

1. 輕量級指針

先來看一下實(shí)現(xiàn)引用計(jì)數(shù)的類LightRefBase,它定義在frameworks/base/include/utils/RefBase.h文件中:

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;}protected:inline ~LightRefBase() { }private:mutable volatile int32_t mCount; };

這個(gè)類很簡單,它只一個(gè)成員變量mCount,這就是引用計(jì)數(shù)器了,它的初始化值為0,另外,這個(gè)類還提供兩個(gè)成員函數(shù)incStrong和decStrong來維護(hù)引用計(jì)數(shù)器的值,這兩個(gè)函數(shù)就是提供給智能指針來調(diào)用的了,這里要注意的是,在decStrong函數(shù)中,如果當(dāng)前引用計(jì)數(shù)值為1,那么當(dāng)減1后就會(huì)變成0,于是就會(huì)delete這個(gè)對象。

前面說過,要實(shí)現(xiàn)自動(dòng)引用計(jì)數(shù),除了要有提供引用計(jì)數(shù)器的基類外,還需要有智能指針類。在Android系統(tǒng)中,配合LightRefBase引用計(jì)數(shù)使用的智能指針類便是sp了,它也是定義在frameworks/base/include/utils/RefBase.h文件中:

template <typename T> class sp { public:typedef typename RefBase::weakref_type weakref_type;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();// Assignmentsp& 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);// Resetvoid clear();// Accessorsinline T& operator* () const { return *m_ptr; }inline T* operator-> () const { return m_ptr; }inline T* get() const { return m_ptr; }// OperatorsCOMPARE(==)COMPARE(!=)COMPARE(>)COMPARE(<)COMPARE(<=)COMPARE(>=)private:template<typename Y> friend class sp;template<typename Y> friend class wp;// Optimization for wp::promote().sp(T* p, weakref_type* refs);T* m_ptr; };

這個(gè)類的內(nèi)容比較多,但是這里我們只關(guān)注它的成員變量m_ptr、構(gòu)造函數(shù)和析構(gòu)函數(shù)。不難看出,成員變量m_ptr就是指向真正的對象了,它是在構(gòu)造函數(shù)里面初始化的。接下來我們就再看一下它的兩個(gè)構(gòu)造函數(shù),一個(gè)是普通構(gòu)造函數(shù),一個(gè)拷貝構(gòu)造函數(shù):

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

這兩個(gè)構(gòu)造函數(shù)都會(huì)首先初始化成員變量m_ptr,然后再調(diào)用m_ptr的incStrong函數(shù)來增加對象的引用計(jì)數(shù),在我們這個(gè)場景中,就是調(diào)用LightRefBase類的incStrong函數(shù)了。

最后,看一下析構(gòu)函數(shù):

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

析構(gòu)函數(shù)也很簡單,只是調(diào)用m_ptr的成員函數(shù)decStrong來減少對象的引用計(jì)數(shù)值,這里就是調(diào)用LightRefBase類的decStrong函數(shù)了,前面我們看到,當(dāng)這個(gè)引用計(jì)數(shù)減1后變成0時(shí),就會(huì)自動(dòng)delete這個(gè)對象了。

輕量級智能指針的實(shí)現(xiàn)原理大概就是這樣了,比較簡單,下面我們再用一個(gè)例子來說明它的用法。

2. 輕量級指針的用法

我們在external目錄下建立一個(gè)C++工程目錄lightpointer,它里面有兩個(gè)文件,一個(gè)lightpointer.cpp文件,另外一個(gè)是Android.mk文件。

源文件lightpointer.cpp的內(nèi)容如下:

#include <stdio.h> #include <utils/RefBase.h>using namespace android;class LightClass : public LightRefBase<LightClass> { public:LightClass(){printf("Construct LightClass Object.");}virtual ~LightClass(){printf("Destory LightClass Object.");} };int main(int argc, char** argv) {LightClass* pLightClass = new LightClass();sp<LightClass> lpOut = pLightClass;printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());{sp<LightClass> lpInner = lpOut;printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());}printf("Light Ref Count: %d.\n", pLightClass->getStrongCount());return 0; }

我們創(chuàng)建一個(gè)自己的類LightClass,繼承了LightRefBase模板類,這樣類LightClass就具有引用計(jì)數(shù)的功能了。在main函數(shù)里面,我們首先new一個(gè)LightClass對象,然后把這個(gè)對象賦值給智能指針lpOut,這時(shí)候通過一個(gè)printf語句來將當(dāng)前對象的引用計(jì)數(shù)值打印出來,從前面的分析可以看出,如果一切正常的話,這里打印出來的引用計(jì)數(shù)值為1。接著,我們又在兩個(gè)大括號里面定義了另外一個(gè)智能指針lpInner,它通過lpOut間接地指向了前面我們所創(chuàng)建的對象,這時(shí)候再次將當(dāng)前對象的引用計(jì)數(shù)值打印出來,從前面的分析也可以看出,如果一切正常的話,這里打印出來的引用計(jì)數(shù)值應(yīng)該為2。程序繼承往下執(zhí)行,當(dāng)出了大括號的范圍的時(shí)候,智能指針對象lpInner就被析構(gòu)了,從前面的分析可以知道,智能指針在析構(gòu)的時(shí)候,會(huì)減少當(dāng)前對象的引用計(jì)數(shù)值,因此,最后一個(gè)printf語句打印出來的引用計(jì)數(shù)器值應(yīng)該為1。當(dāng)main函數(shù)執(zhí)行完畢后,智能指針lpOut也會(huì)被析構(gòu),被析構(gòu)時(shí),它會(huì)再次減少當(dāng)前對象的引用計(jì)數(shù),這時(shí)候,對象的引用計(jì)數(shù)值就為0了,于是,它就會(huì)被delete了。

編譯腳本文件Android.mk的內(nèi)容如下:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := lightpointer LOCAL_SRC_FILES := lightpointer.cpp LOCAL_SHARED_LIBRARIES := \libcutils \libutils include $(BUILD_EXECUTABLE)

最后,我們參照如何單獨(dú)編譯Android源代碼中的模塊一文,使用mmm命令對工程進(jìn)行編譯:

USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/lightpointer

編譯之后,就可以打包了:

USER-NAME@MACHINE-NAME:~/Android$ make snod

最后得到可執(zhí)行程序lightpointer就位于設(shè)備上的/system/bin/目錄下。啟動(dòng)模擬器,通過adb shell命令進(jìn)入到模擬器終端,進(jìn)入到/system/bin/目錄,執(zhí)行l(wèi)ightpointer可執(zhí)行程序,驗(yàn)證程序是否按照我們設(shè)計(jì)的邏輯運(yùn)行:

USER-NAME@MACHINE-NAME:~/Android$ adb shell root@android:/ # cd system/bin/ root@android:/system/bin # ./lightpointer Construct LightClass Object. Light Ref Count: 1. Light Ref Count: 2. Light Ref Count: 1. Destory LightClass Object.

這里可以看出,程序一切都是按照我們的設(shè)計(jì)來運(yùn)行,這也驗(yàn)證了我們上面分析的輕量級智能指針的實(shí)現(xiàn)原理。

3. 強(qiáng)指針

強(qiáng)指針?biāo)褂玫囊糜?jì)數(shù)類為RefBase,它LightRefBase類要復(fù)雜多了,所以才稱后者為輕量級的引用計(jì)數(shù)基類吧。我們先來看看RefBase類的實(shí)現(xiàn),它定義在frameworks/base/include/utils/RefBase.h文件中:

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);bool attemptIncStrong(const void* id);//! This is only safe if you have set OBJECT_LIFETIME_FOREVER.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);}protected:RefBase();virtual ~RefBase();//! Flags for extendObjectLifetime()enum {OBJECT_LIFETIME_WEAK = 0x0001,OBJECT_LIFETIME_FOREVER = 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; };

RefBase類和LightRefBase類一樣,提供了incStrong和decStrong成員函數(shù)來操作它的引用計(jì)數(shù)器;而RefBase類與LightRefBase類最大的區(qū)別是,它不像LightRefBase類一樣直接提供一個(gè)整型值(mutable volatile int32_t mCount)來維護(hù)對象的引用計(jì)數(shù),前面我們說過,復(fù)雜的引用計(jì)數(shù)技術(shù)同時(shí)支持強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù),在RefBase類中,這兩種計(jì)數(shù)功能是通過其成員變量mRefs來提供的。

RefBase類的成員變量mRefs的類型為weakref_impl指針,它實(shí)現(xiàn)在frameworks/base/libs/utils/RefBase.cpp文件中:

class RefBase::weakref_impl : public RefBase::weakref_type { public:volatile int32_t mStrong;volatile int32_t mWeak;RefBase* const mBase;volatile int32_t mFlags;#if !DEBUG_REFSweakref_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) { }#elseweakref_impl(RefBase* base): mStrong(INITIAL_STRONG_VALUE), mWeak(0), mBase(base), mFlags(0), mStrongRefs(NULL), mWeakRefs(NULL), mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT), mRetain(false){//LOGI("NEW weakref_impl %p for RefBase %p", this, base);}~weakref_impl(){LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");}void addStrongRef(const void* id){addRef(&mStrongRefs, id, mStrong);}void removeStrongRef(const void* id){if (!mRetain)removeRef(&mStrongRefs, id);elseaddRef(&mStrongRefs, id, -mStrong);}void addWeakRef(const void* id){addRef(&mWeakRefs, id, mWeak);}void removeWeakRef(const void* id){if (!mRetain)removeRef(&mWeakRefs, id);elseaddRef(&mWeakRefs, id, -mWeak);}void trackMe(bool track, bool retain){mTrackEnabled = track;mRetain = retain;}......private:struct ref_entry{ref_entry* next;const void* id; #if DEBUG_REFS_CALLSTACK_ENABLEDCallStack stack; #endifint32_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_ENABLEDref->stack.update(2); #endifref->next = *refs;*refs = ref;}}void removeRef(ref_entry** refs, const void* id){if (mTrackEnabled) {AutoMutex _l(mMutex);ref_entry* ref = *refs;while (ref != NULL) {if (ref->id == id) {*refs = ref->next;delete ref;return;}refs = &ref->next;ref = *refs;}LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",id, mBase, this);}}......Mutex mMutex;ref_entry* mStrongRefs;ref_entry* mWeakRefs;bool mTrackEnabled;// Collect stack traces on addref and removeref, instead of deleting the stack references// on removeref that match the address ones.bool mRetain;...... #endif };

這個(gè)類看起來實(shí)現(xiàn)得很復(fù)雜,其實(shí)不然,這個(gè)類的實(shí)現(xiàn)可以分成兩部分:

#if !DEBUG_REFS......#else

編譯指令之間的這部分源代碼是Release版本的源代碼,它的成員函數(shù)都是空實(shí)現(xiàn);

#else ......#endif

編譯指令之間的部分源代碼是Debug版本的源代碼,它的成員函數(shù)都是有實(shí)現(xiàn)的,實(shí)現(xiàn)這些函數(shù)的目的都是為了方便開發(fā)人員調(diào)試引用計(jì)數(shù)用的,除此之外,還在內(nèi)部實(shí)現(xiàn)了一個(gè)結(jié)構(gòu)體ref_entry:

struct ref_entry {ref_entry* next;const void* id; #if DEBUG_REFS_CALLSTACK_ENABLEDCallStack stack; #endifint32_t ref; };

這個(gè)結(jié)構(gòu)體也是為了方便調(diào)試而使用的,我們可以不關(guān)注這部分用于調(diào)試的代碼。

總的來說,weakref_impl類只要提供了以下四個(gè)成員變量來維護(hù)對象的引用計(jì)數(shù):

volatile int32_t mStrong; volatile int32_t mWeak; RefBase* const mBase; volatile int32_t mFlags;

其中mStrong和mWeak分別表示對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù);RefBase類包含了一個(gè)weakref_impl類指針mRefs,而這里的weakref_impl類也有一個(gè)成員變量mBase來指向它的宿主類RefBase;mFlags是一個(gè)標(biāo)志位,它指示了維護(hù)對象引用計(jì)數(shù)所使用的策略,后面我們將會(huì)分析到,它的取值為0,或者以下的枚舉值:

//! Flags for extendObjectLifetime() enum {OBJECT_LIFETIME_WEAK = 0x0001,OBJECT_LIFETIME_FOREVER = 0x0003 };

這里我們還需要注意的一點(diǎn)的是,從weakref_impl的類名來看,它應(yīng)該是一個(gè)實(shí)現(xiàn)類,那么,就必然有一個(gè)對應(yīng)的接口類,這個(gè)對應(yīng)的接口類的就是RefBase類內(nèi)部定義的weakref_type類了,這是一種把類的實(shí)現(xiàn)與接口定義分離的設(shè)計(jì)方法。學(xué)習(xí)過設(shè)計(jì)模式的讀者應(yīng)該知道,在設(shè)計(jì)模式里面,非常強(qiáng)調(diào)類的接口定義和類的實(shí)現(xiàn)分離,以便利于后續(xù)擴(kuò)展和維護(hù),這里就是用到了這種設(shè)計(jì)思想。

說了這多,RefBase類給人的感覺還是挺復(fù)雜的,不要緊,我們一步步來,先通過下面這個(gè)圖來梳理一下這些類之間的關(guān)系:

從這個(gè)類圖可以看出,每一個(gè)RefBase對象包含了一個(gè)weakref_impl對象,而weakref_impl對象實(shí)現(xiàn)了weakref_type接口,同時(shí)它可以包含多個(gè)ref_entry對象,前面說過,ref_entry是調(diào)試用的一個(gè)結(jié)構(gòu)體,實(shí)際使用中可以不關(guān)注。

提供引用計(jì)數(shù)器的類RefBase我們就暫時(shí)介紹到這里,后面我們再結(jié)合智能指針類一起分析,現(xiàn)在先來看看強(qiáng)指針類和弱指針類的定義。強(qiáng)指針類的定義我們在前面介紹輕量級指針的時(shí)候已經(jīng)見到了,就是sp類了,這里就不再把它的代碼列出來了。我們來看看它的構(gòu)造函數(shù)的實(shí)現(xiàn):

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

這里傳進(jìn)來的參數(shù)other一定是繼承于RefBase類的,因此,在函數(shù)的內(nèi)部,它調(diào)用的是RefBase類的incStrong函數(shù),它定義在frameworks/base/libs/utils/RefBase.cpp文件中:

void RefBase::incStrong(const void* id) const {weakref_impl* const refs = mRefs;refs->addWeakRef(id);refs->incWeak(id);refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);#if PRINT_REFS LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);#endif if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); const_cast<RefBase*>(this)->onFirstRef(); }

成員變量mRefs是在RefBase類的構(gòu)造函數(shù)中創(chuàng)建的:

在這個(gè)incStrong函數(shù)中,主要做了三件事情:

一是增加弱引用計(jì)數(shù):

refs->addWeakRef(id); refs->incWeak(id);

二是增加強(qiáng)引用計(jì)數(shù):

refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong);

三是如果發(fā)現(xiàn)是首次調(diào)用這個(gè)對象的incStrong函數(shù),就會(huì)調(diào)用一個(gè)這個(gè)對象的onFirstRef函數(shù),讓對象有機(jī)會(huì)在對象被首次引用時(shí)做一些處理邏輯:

if (c != INITIAL_STRONG_VALUE) {return; }android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); const_cast<RefBase*>(this)->onFirstRef();

這里的c返回的是refs->mStrong加1前的值,如果發(fā)現(xiàn)等于INITIAL_STRONG_VALUE,就說明這個(gè)對象的強(qiáng)引用計(jì)數(shù)是第一次被增加,因此,refs->mStrong就是初始化為INITIAL_STRONG_VALUE的,它的值為:

#define INITIAL_STRONG_VALUE (1<<28)

這個(gè)值加1后等于1<<28 + 1,不等于1,因此,后面要再減去-INITIAL_STRONG_VALUE,于是,refs->mStrong就等于1了,就表示當(dāng)前對象的強(qiáng)引用計(jì)數(shù)值為1了,這與這個(gè)對象是第一次被增加強(qiáng)引用計(jì)數(shù)值的邏輯是一致的。

回過頭來看弱引用計(jì)數(shù)是如何增加的,首先是調(diào)用weakref_impl類的addWeakRef函數(shù),我們知道,在Release版本中,這個(gè)函數(shù)也不做,而在Debug版本中,這個(gè)函數(shù)增加了一個(gè)ref_entry對象到了weakref_impl對象的mWeakRefs列表中,表示此weakref_impl對象的弱引用計(jì)數(shù)被增加了一次。接著又調(diào)用了weakref_impl類的incWeak函數(shù),真正增加弱引用計(jì)數(shù)值就是在這個(gè)函數(shù)實(shí)現(xiàn)的了,weakref_impl類的incWeak函數(shù)繼承于其父類weakref_type的incWeak函數(shù):

void RefBase::weakref_type::incWeak(const void* id) {weakref_impl* const impl = static_cast<weakref_impl*>(this);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); }

增加弱引用計(jì)數(shù)是下面語句執(zhí)行的:

const int32_t c = android_atomic_inc(&impl->mWeak);

但是前面為什么又調(diào)用了一次addWeakRef函數(shù)呢?前面不是已經(jīng)調(diào)用過了嗎?在Release版本中,因?yàn)閣eakref_impl類的addWeakRef函數(shù)是空實(shí)現(xiàn),這里再調(diào)用一次沒有什么害處,但是如果在Debug版本,豈不是冗余了嗎?搞不清,有人問過負(fù)責(zé)開發(fā)Android系統(tǒng)Binder通信機(jī)制模塊的作者Dianne Hackborn這個(gè)問題,他是這樣回答的:

Ah I see. Well the debug code may be broken, though I wouldn't leap to that
conclusion without actually testing it; I know it has been used in the
past. Anyway, these things get compiled out in non-debug builds, so there
is no reason to change them unless you are actually trying to use this debug
code and it isn't working and need to do this to fix it.

既然他也不知道怎么回事,我們也不必深究了,知道有這么回事就行。

這里總結(jié)一下強(qiáng)指針類sp在其構(gòu)造函數(shù)里面所做的事情就是分別為目標(biāo)對象的強(qiáng)引用計(jì)數(shù)和弱引和計(jì)數(shù)增加了1。

再來看看強(qiáng)指針類的析構(gòu)函數(shù)的實(shí)現(xiàn):

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

同樣,這里的m_ptr指向的目標(biāo)對象一定是繼承了RefBase類的,因此,這里調(diào)用的是RefBase類的decStrong函數(shù),這也是定義在frameworks/base/libs/utils/RefBase.cpp文件中:

void RefBase::decStrong(const void* id) const {weakref_impl* const refs = mRefs;refs->removeStrongRef(id);const int32_t c = android_atomic_dec(&refs->mStrong); #if PRINT_REFSLOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); #endifLOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);if (c == 1) {const_cast<RefBase*>(this)->onLastStrongRef(id);if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {delete this;}}refs->removeWeakRef(id);refs->decWeak(id); }

這里的refs->removeStrongRef函數(shù)調(diào)用語句是對應(yīng)前面在RefBase::incStrong函數(shù)里的refs->addStrongRef函數(shù)調(diào)用語句的,在Release版本中,這也是一個(gè)空實(shí)現(xiàn)函數(shù),真正實(shí)現(xiàn)強(qiáng)引用計(jì)數(shù)減1的操作是下面語句:

const int32_t c = android_atomic_dec(&refs->mStrong);

如果發(fā)現(xiàn)減1前,此對象的強(qiáng)引用計(jì)數(shù)為1,就說明從此以后,就再?zèng)]有地方引用這個(gè)目標(biāo)對象了,這時(shí)候,就要看看是否要delete這個(gè)目標(biāo)對象了:

if (c == 1) {const_cast<RefBase*>(this)->onLastStrongRef(id);if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {delete this;} }

在強(qiáng)引用計(jì)數(shù)為0的情況下,如果對象的標(biāo)志位OBJECT_LIFETIME_WEAK被設(shè)置了,就說明這個(gè)對象的生命周期是受弱引用計(jì)數(shù)所控制的,因此,這時(shí)候就不能delete對象,要等到弱引用計(jì)數(shù)也為0的情況下,才能delete這個(gè)對象。

接下來的ref->removeWeakRef函數(shù)調(diào)用語句是對應(yīng)前面在RefBase::incStrong函數(shù)里的refs->addWeakRef函數(shù)調(diào)用語句的,在Release版本中,這也是一個(gè)空實(shí)現(xiàn)函數(shù),真正實(shí)現(xiàn)強(qiáng)引用計(jì)數(shù)減1的操作下面的refs->decWeak函數(shù),weakref_impl類沒有實(shí)現(xiàn)自己的decWeak函數(shù),它繼承了weakref_type類的decWeak函數(shù):

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);LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);if (c != 1) return;if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {if (impl->mStrong == INITIAL_STRONG_VALUE)delete impl->mBase;else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);delete impl;}} else {impl->mBase->onLastWeakRef(id);if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {delete impl->mBase;}} }

這里又一次調(diào)用了weakref_impl對象的removeWeakRef函數(shù),這也是和RefBase::weakref_type::incWeak函數(shù)里面的impl->addWeakRef語句所對應(yīng)的,實(shí)現(xiàn)弱引用計(jì)數(shù)減1的操作是下面語句:

const int32_t c = android_atomic_dec(&impl->mWeak);

減1前如果發(fā)現(xiàn)不等于1,那么就什么也不用做就返回了,如果發(fā)現(xiàn)等于1,就說明當(dāng)前對象的弱引用計(jì)數(shù)值為0了,這時(shí)候,就要看看是否要delete這個(gè)對象了:

if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {if (impl->mStrong == INITIAL_STRONG_VALUE)delete impl->mBase;else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);delete impl;} } else {impl->mBase->onLastWeakRef(id);if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {delete impl->mBase;} }

如果目標(biāo)對象的生命周期是不受弱引用計(jì)數(shù)控制的,就執(zhí)行下面語句:

if (impl->mStrong == INITIAL_STRONG_VALUE)delete impl->mBase; else { // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);delete impl; }

這個(gè)代碼段是什么意思呢?這里是減少對象的弱引用計(jì)數(shù)的地方,如果調(diào)用到這里,那么就說明前面一定有增加過此對象的弱引用計(jì)數(shù),而增加對象的弱引用計(jì)數(shù)有兩種場景的,一種場景是增加對象的強(qiáng)引用計(jì)數(shù)的時(shí)候,會(huì)同時(shí)增加對象的弱引用計(jì)數(shù),另一種場景是當(dāng)我們使用一個(gè)弱指針來指向?qū)ο髸r(shí),在弱指針對象的構(gòu)造函數(shù)里面,也會(huì)增加對象的弱引用計(jì)數(shù),不過這時(shí)候,就只是增加對象的弱引用計(jì)數(shù)了,并沒有同時(shí)增加對象的強(qiáng)引用計(jì)數(shù)。因此,這里在減少對象的弱引用計(jì)數(shù)時(shí),就要分兩種情況來考慮。

如果是前一種場景,這里的impl->mStrong就必然等于0,而不會(huì)等于INITIAL_STRONG_VALUE值,因此,這里就不需要delete目標(biāo)對象了(impl->mBase),因?yàn)榍懊娴腞efBase::decStrong函數(shù)會(huì)負(fù)責(zé)delete這個(gè)對象。這里唯一需要做的就是把weakref_impl對象delete掉,但是,為什么要在這里delete這個(gè)weakref_impl對象呢?這里的weakref_impl對象是在RefBase的構(gòu)造函數(shù)里面new出來的,理論上說應(yīng)該在在RefBase的析構(gòu)函數(shù)里delete掉這個(gè)weakref_impl對象的。在RefBase的析構(gòu)函數(shù)里面,的確是會(huì)做這件事情:

RefBase::~RefBase() { // LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);if (mRefs->mWeak == 0) { // LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);delete mRefs;} }

但是不要忘記,在這個(gè)場景下,目標(biāo)對象是前面的RefBase::decStrong函數(shù)delete掉的,這時(shí)候目標(biāo)對象就會(huì)被析構(gòu),但是它的弱引用計(jì)數(shù)值尚未執(zhí)行減1操作,因此,這里的mRefs->mWeak == 0條件就不成立,于是就不會(huì)delete這個(gè)weakref_impl對象,因此,就延遲到執(zhí)行這里decWeak函數(shù)時(shí)再執(zhí)行。

如果是后一種情景,這里的impl->mStrong值就等于INITIAL_STRONG_VALUE了,這時(shí)候由于沒有地方會(huì)負(fù)責(zé)delete目標(biāo)對象,因此,就需要把目標(biāo)對象(imp->mBase)delete掉了,否則就會(huì)造成內(nèi)存泄漏。在delete這個(gè)目標(biāo)對象的時(shí)候,就會(huì)執(zhí)行RefBase類的析構(gòu)函數(shù),這時(shí)候目標(biāo)對象的弱引用計(jì)數(shù)等于0,于是,就會(huì)把weakref_impl對象也一起delete掉了。

回到外層的if語句中,如果目標(biāo)對象的生命周期是受弱引用計(jì)數(shù)控制的,就執(zhí)行下面語句:

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

理論上說,如果目標(biāo)對象的生命周期是受弱引用計(jì)數(shù)控制的,那么當(dāng)強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)都為0的時(shí)候,這時(shí)候就應(yīng)該delete目標(biāo)對象了,但是這里還有另外一層控制,我們可以設(shè)置目標(biāo)對象的標(biāo)志值為OBJECT_LIFETIME_FOREVER,即目標(biāo)對象的生命周期完全不受強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)控制,在這種情況下,即使目標(biāo)對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)都同時(shí)為0,這里也不能delete這個(gè)目標(biāo)對象,那么,由誰來delete掉呢?當(dāng)然是誰new出來的,就誰來delete掉了,這時(shí)候智能指針就完全退化為普通指針了,這里的智能指針設(shè)計(jì)的非常強(qiáng)大。

分析到這里,有必要小結(jié)一下:

A. 如果對象的標(biāo)志位被設(shè)置為0,那么只要發(fā)現(xiàn)對象的強(qiáng)引用計(jì)數(shù)值為0,那就會(huì)自動(dòng)delete掉這個(gè)對象;

B. 如果對象的標(biāo)志位被設(shè)置為OBJECT_LIFETIME_WEAK,那么只有當(dāng)對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)都為0的時(shí)候,才會(huì)自動(dòng)delete掉這個(gè)對象;

C. 如果對象的標(biāo)志位被設(shè)置為OBJECT_LIFETIME_FOREVER,那么對象就永遠(yuǎn)不會(huì)自動(dòng)被delete掉,誰new出來的對象誰來delete掉。

到了這里,強(qiáng)指針就分析完成了,最后來分析弱指針。

4. 弱指針

弱指針?biāo)褂玫囊糜?jì)數(shù)類與強(qiáng)指針一樣,都是RefBase類,因此,這里就不再重復(fù)介紹了,我們直接來弱指針的實(shí)現(xiàn),它定義在frameworks/base/include/utils/RefBase.h文件中:

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();// Assignmentwp& 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 spsp<T> promote() const;// Resetvoid clear();// Accessorsinline weakref_type* get_refs() const { return m_refs; }inline T* unsafe_get() const { return m_ptr; }// OperatorsCOMPARE_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;T* m_ptr;weakref_type* m_refs; };

與強(qiáng)指針類相比,它們都有一個(gè)成員變量m_ptr指向目標(biāo)對象,但是弱指針還有一個(gè)額外的成員變量m_refs,它的類型是weakref_type指針,下面我們分析弱指針的構(gòu)造函數(shù)時(shí)再看看它是如果初始化的。這里我們需要關(guān)注的仍然是弱指針的構(gòu)造函數(shù)和析構(gòu)函數(shù)。

先來看構(gòu)造函數(shù):

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

這里的參數(shù)other一定是繼承了RefBase類,因此,這里調(diào)用了RefBase類的createWeak函數(shù),它定義在frameworks/base/libs/utils/RefBase.cpp文件中:

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

這里的成員變量mRefs的類型為weakref_impl指針,weakref_impl類的incWeak函數(shù)我們在前面已經(jīng)看過了,它的作用就是增加對象的弱引用計(jì)數(shù)。函數(shù)最后返回mRefs,于是,弱指針對象的成員變量m_refs就指向目標(biāo)對象的weakref_impl對象了。

再來看析構(gòu)函數(shù):

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

這里,弱指針在析構(gòu)的時(shí)候,與強(qiáng)指針析構(gòu)不一樣,它直接就調(diào)用目標(biāo)對象的weakref_impl對象的decWeak函數(shù)來減少弱引用計(jì)數(shù)了,當(dāng)弱引用計(jì)數(shù)為0的時(shí)候,就會(huì)根據(jù)在目標(biāo)對象的標(biāo)志位(0、OBJECT_LIFETIME_WEAK或者OBJECT_LIFETIME_FOREVER)來決定是否要delete目標(biāo)對象,前面我們已經(jīng)介紹過了,這里就不再介紹了。

分析到這里,弱指針還沒介紹完,它最重要的特性我們還沒有分析到。前面我們說過,弱指針的最大特點(diǎn)是它不能直接操作目標(biāo)對象,這是怎么樣做到的呢?秘密就在于弱指針類沒有重載*和->操作符號,而強(qiáng)指針重載了這兩個(gè)操作符號。但是,如果我們要操作目標(biāo)對象,應(yīng)該怎么辦呢,這就要把弱指針升級為強(qiáng)指針了:

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

升級的方式就使用成員變量m_ptr和m_refs來構(gòu)造一個(gè)強(qiáng)指針sp,這里的m_ptr為指目標(biāo)對象的一個(gè)指針,而m_refs則是指向目標(biāo)對象里面的weakref_impl對象。

我們再來看看這個(gè)強(qiáng)指針的構(gòu)造過程:

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

主要就是初始化指向目標(biāo)對象的成員變量m_ptr了,如果目標(biāo)對象還存在,這個(gè)m_ptr就指向目標(biāo)對象,如果目標(biāo)對象已經(jīng)不存在,m_ptr就為NULL,升級成功與否就要看refs->attemptIncStrong函數(shù)的返回結(jié)果了:

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_REFSLOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); #endifif (curCount == INITIAL_STRONG_VALUE) {android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);impl->mBase->onFirstRef();}return true; }

這個(gè)函數(shù)的作用是試圖增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù),但是有可能會(huì)失敗,失敗的原因可能是因?yàn)槟繕?biāo)對象已經(jīng)被delete掉了,或者是其它的原因,下面會(huì)分析到。前面我們在討論強(qiáng)指針的時(shí)候說到,增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù)的同時(shí),也會(huì)增加目標(biāo)對象的弱引用計(jì)數(shù),因此,函數(shù)在開始的地方首先就是調(diào)用incWeak函數(shù)來先增加目標(biāo)對象的引用計(jì)數(shù),如果后面試圖增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù)失敗時(shí),會(huì)調(diào)用decWeak函數(shù)來回滾前面的incWeak操作。

這里試圖增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù)時(shí),分兩種情況討論,一種情況是此時(shí)目標(biāo)對象正在被其它強(qiáng)指針引用,即它的強(qiáng)引用計(jì)數(shù)大于0,并且不等于INITIAL_STRONG_VALUE,另一種情況是此時(shí)目標(biāo)對象沒有被任何強(qiáng)指針引用,即它的強(qiáng)引用計(jì)數(shù)小于等于0,或者等于INITIAL_STRONG_VALUE。

第一種情況比較簡單,因?yàn)檫@時(shí)候說明目標(biāo)對象一定存在,因此,是可以將這個(gè)弱指針提升為強(qiáng)指針的,在這種情況下,只要簡單地增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值就行了:

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

當(dāng)我們在這里對目標(biāo)對象的強(qiáng)引用計(jì)數(shù)執(zhí)行加1操作時(shí),要保證原子性,因?yàn)槠渌胤揭灿锌赡苷趯@個(gè)目標(biāo)對象的強(qiáng)引用計(jì)數(shù)執(zhí)行加1的操作,前面我們一般是調(diào)用android_atomic_inc函數(shù)來完成,但是這里是通過調(diào)用android_atomic_cmpxchg函數(shù)來完成,android_atomic_cmpxchg函數(shù)是體系結(jié)構(gòu)相關(guān)的函數(shù),在提供了一些特殊的指令的體系結(jié)構(gòu)上,調(diào)用android_atomic_cmpxchg函數(shù)來執(zhí)行加1操作的效率會(huì)比調(diào)用android_atomic_inc函數(shù)更高一些。函數(shù)android_atomic_cmpxchg是在system/core/include/cutils/atomic.h文件中定義的一個(gè)宏:

int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,volatile int32_t* addr);#define android_atomic_cmpxchg android_atomic_release_cas

它實(shí)際執(zhí)行的函數(shù)是android_atomic_release_cas,這個(gè)函數(shù)的工作原理大概是這樣的:如果它發(fā)現(xiàn)addr == oldvalue,就會(huì)執(zhí)行addr = newvalue的操作,然后返回0,否則什么也不做,返回1。在我們討論的這個(gè)場景中,oldvalue等于curCount,而newvalue等于curCount + 1,于是,在addr == oldvalue的條件下,就相當(dāng)于是對目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值增加了1。什么情況下addr != oldvalue呢?在調(diào)用android_atomic_release_cas函數(shù)之前,oldvalue和值就是從地址addr讀出來的,如果在執(zhí)行android_atomic_release_cas函數(shù)的時(shí)候,有其它地方也對地址addr進(jìn)行操作,那么就會(huì)有可能出現(xiàn)*addr != oldvalue的情況,這時(shí)候就說明其它地方也在操作目標(biāo)對象的強(qiáng)引用計(jì)數(shù)了,因此,這里就不能執(zhí)行增加目標(biāo)對象的強(qiáng)引用計(jì)數(shù)的操作了,它必須要等到其它地方操作完目標(biāo)對象的強(qiáng)引用計(jì)數(shù)之后再重新執(zhí)行,這就是為什么要通過一個(gè)while循環(huán)來執(zhí)行了。

第二種情況比較復(fù)雜一點(diǎn),因?yàn)檫@時(shí)候目標(biāo)對象可能還存在,也可能不存了,這要根據(jù)實(shí)際情況來判斷。如果此時(shí)目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值等于INITIAL_STRONG_VALUE,說明此目標(biāo)對象還從未被強(qiáng)指針引用過,這時(shí)候弱指針能夠被提升為強(qiáng)指針的條件就為:

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

即如果目標(biāo)對象的生命周期只受到強(qiáng)引用計(jì)數(shù)控制或者在目標(biāo)對象的具體實(shí)現(xiàn)中總是允許這種情況發(fā)生。怎么理解呢?如果目標(biāo)對象的生命周期只受強(qiáng)引用計(jì)數(shù)控制(它的標(biāo)志位mFlags為0),而這時(shí)目標(biāo)對象又還未被強(qiáng)指針引用過,它自然就不會(huì)被delete掉,因此,這時(shí)候可以判斷出目標(biāo)對象是存在的;如果目標(biāo)對象的生命周期受弱引用計(jì)數(shù)控制(OBJECT_LIFETIME_WEAK),這時(shí)候由于目標(biāo)對象正在被弱指針引用,因此,弱引用計(jì)數(shù)一定不為0,目標(biāo)對象一定存在;如果目標(biāo)對象的生命周期不受引用計(jì)數(shù)控制(BJECT_LIFETIME_FOREVER),這時(shí)候目標(biāo)對象也是下在被弱指針引用,因此,目標(biāo)對象的所有者必須保證這個(gè)目標(biāo)對象還沒有被delete掉,否則就會(huì)出問題了。在后面兩種場景下,因?yàn)槟繕?biāo)對象的生命周期都是不受強(qiáng)引用計(jì)數(shù)控制的,而現(xiàn)在又要把弱指針提升為強(qiáng)指針,就需要進(jìn)一步調(diào)用目標(biāo)對象的onIncStrongAttempted來看看是否允許這種情況發(fā)生,這又該怎么理解呢?可以這樣理解,目標(biāo)對象的設(shè)計(jì)者可能本身就不希望這個(gè)對象被強(qiáng)指針引用,只能通過弱指針來引用它,因此,這里它就可以重載其父類的onIncStrongAttempted函數(shù),然后返回false,這樣就可以阻止弱指針都被提升為強(qiáng)指針。在RefBase類中,其成員函數(shù)onIncStrongAttempted默認(rèn)是返回true的:

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

如果此時(shí)目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值小于等于0,那就說明該對象之前一定被強(qiáng)指針引用過,這時(shí)候就必須保證目標(biāo)對象是被弱引用計(jì)數(shù)控制的(BJECT_LIFETIME_WEAK),否則的話,目標(biāo)對象就已經(jīng)被delete了。同樣,這里也要調(diào)用一下目標(biāo)對象的onIncStrongAttempted成員函數(shù),來詢問一下目標(biāo)對象在強(qiáng)引用計(jì)數(shù)值小于等于0的時(shí)候,是否允計(jì)將弱指針提升為強(qiáng)指針。下面這個(gè)代碼段就是執(zhí)行上面所說的邏輯:

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

繼續(xù)往下看:

if (!allow) {decWeak(id);return false; } curCount = android_atomic_inc(&impl->mStrong);

如果allow值為false,那么就說明不允計(jì)把這個(gè)弱指針提升為強(qiáng)指針,因此就返回false了,在返回之前,要先調(diào)用decWeak函數(shù)來減少目標(biāo)對象的弱引用計(jì)數(shù),因?yàn)楹瘮?shù)的開頭不管三七二十一,首先就調(diào)用了incWeak來增加目標(biāo)對象的弱引用計(jì)數(shù)值。

函數(shù)attemptIncStrong的主體邏輯大概就是這樣了,比較復(fù)雜,讀者要細(xì)細(xì)體會(huì)一下。函數(shù)的最后,如果此弱指針是允計(jì)提升為強(qiáng)指針的,并且此目標(biāo)對象是第一次被強(qiáng)指針引用,還需要調(diào)整一下目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值:

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

這個(gè)邏輯我們在前面分析強(qiáng)指針時(shí)已經(jīng)分析過了,這里不再詳述。

分析到這里,弱指針就介紹完了。強(qiáng)指針和弱指針的關(guān)系比較密切,同時(shí)它們也比較復(fù)雜,下面我們再舉一個(gè)例子來說明強(qiáng)指針和弱指針的用法,同時(shí)也驗(yàn)證一下它們的實(shí)現(xiàn)原理。

5. 強(qiáng)指針和弱指針的用法

參考在Ubuntu上為Android系統(tǒng)內(nèi)置C可執(zhí)行程序測試Linux內(nèi)核驅(qū)動(dòng)程序一文,我們在external目錄下建立一個(gè)C++工程目錄weightpointer,它里面有兩個(gè)文件,一個(gè)weightpointer.cpp文件,另外一個(gè)是Android.mk文件。

源文件weightpointer.cpp的內(nèi)容如下:

#include <stdio.h> #include <utils/RefBase.h>#define INITIAL_STRONG_VALUE (1<<28)using namespace android;class WeightClass : public RefBase { public:void printRefCount(){int32_t strong = getStrongCount();weakref_type* ref = getWeakRefs();printf("-----------------------\n");printf("Strong Ref Count: %d.\n", (strong == INITIAL_STRONG_VALUE ? 0 : strong));printf("Weak Ref Count: %d.\n", ref->getWeakCount());printf("-----------------------\n");} };class StrongClass : public WeightClass { public:StrongClass(){printf("Construct StrongClass Object.\n");}virtual ~StrongClass(){printf("Destory StrongClass Object.\n");} };class WeakClass : public WeightClass { public:WeakClass(){extendObjectLifetime(OBJECT_LIFETIME_WEAK);printf("Construct WeakClass Object.\n");}virtual ~WeakClass(){printf("Destory WeakClass Object.\n");} };class ForeverClass : public WeightClass { public:ForeverClass(){extendObjectLifetime(OBJECT_LIFETIME_FOREVER);printf("Construct ForeverClass Object.\n");}virtual ~ForeverClass(){printf("Destory ForeverClass Object.\n");} };void TestStrongClass(StrongClass* pStrongClass) {wp<StrongClass> wpOut = pStrongClass;pStrongClass->printRefCount();{sp<StrongClass> spInner = pStrongClass;pStrongClass->printRefCount();}sp<StrongClass> spOut = wpOut.promote();printf("spOut: %p.\n", spOut.get()); }void TestWeakClass(WeakClass* pWeakClass) {wp<WeakClass> wpOut = pWeakClass;pWeakClass->printRefCount();{sp<WeakClass> spInner = pWeakClass;pWeakClass->printRefCount();}pWeakClass->printRefCount();sp<WeakClass> spOut = wpOut.promote();printf("spOut: %p.\n", spOut.get()); }void TestForeverClass(ForeverClass* pForeverClass) {wp<ForeverClass> wpOut = pForeverClass;pForeverClass->printRefCount();{sp<ForeverClass> spInner = pForeverClass;pForeverClass->printRefCount();} }int main(int argc, char** argv) {printf("Test Strong Class: \n");StrongClass* pStrongClass = new StrongClass();TestStrongClass(pStrongClass);printf("\nTest Weak Class: \n");WeakClass* pWeakClass = new WeakClass();TestWeakClass(pWeakClass);printf("\nTest Froever Class: \n");ForeverClass* pForeverClass = new ForeverClass();TestForeverClass(pForeverClass);pForeverClass->printRefCount();delete pForeverClass;return 0; }

首先定義了一個(gè)基類WeightClass,繼承于RefBase類,它只有一個(gè)成員函數(shù)printRefCount,作用是用來輸出引用計(jì)數(shù)。接著分別定義了三個(gè)類StrongClass、WeakClass和ForeverClass,其中實(shí)例化StrongClass類的得到的對象的標(biāo)志位為默認(rèn)值0,實(shí)例化WeakClass類的得到的對象的標(biāo)志位為OBJECT_LIFETIME_WEAK,實(shí)例化ForeverClass類的得到的對象的標(biāo)志位為OBJECT_LIFETIME_FOREVER,后兩者都是通過調(diào)用RefBase類的extendObjectLifetime成員函數(shù)來設(shè)置的。

在main函數(shù)里面,分別實(shí)例化了這三個(gè)類的對象出來,然后分別傳給TestStrongClass函數(shù)、TestWeakClass函數(shù)和TestForeverClass函數(shù)來說明智能指針的用法,我們主要是通過考察它們的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)來驗(yàn)證智能指針的實(shí)現(xiàn)原理。

編譯腳本文件Android.mk的內(nèi)容如下:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := weightpointer LOCAL_SRC_FILES := weightpointer.cpp LOCAL_SHARED_LIBRARIES := \libcutils \libutils include $(BUILD_EXECUTABLE)

最后,我們參照如何單獨(dú)編譯Android源代碼中的模塊一文,使用mmm命令對工程進(jìn)行編譯:

USER-NAME@MACHINE-NAME:~/Android$ mmm ./external/weightpointer

編譯之后,就可以打包了:

USER-NAME@MACHINE-NAME:~/Android$ make snod

最后得到可執(zhí)行程序weightpointer就位于設(shè)備上的/system/bin/目錄下。啟動(dòng)模擬器,通過adb shell命令進(jìn)入到模擬器終端,進(jìn)入到/system/bin/目錄,執(zhí)行weightpointer可執(zhí)行程序,驗(yàn)證程序是否按照我們設(shè)計(jì)的邏輯運(yùn)行:

USER-NAME@MACHINE-NAME:~/Android$ adb shell root@android:/ # cd system/bin/ root@android:/system/bin # ./weightpointer

執(zhí)行TestStrongClass函數(shù)的輸出為:

Test Strong Class: Construct StrongClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- Destory StrongClass Object. spOut: 0x0.

在TestStrongClass函數(shù)里面,首先定義一個(gè)弱批針wpOut指向從main函數(shù)傳進(jìn)來的StrongClass對象,這時(shí)候我們可以看到StrongClass對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)值分別為0和1;接著在一個(gè)大括號里面定義一個(gè)強(qiáng)指針spInner指向這個(gè)StrongClass對象,這時(shí)候我們可以看到StrongClass對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)值分別為1和2;當(dāng)程序跳出了大括號之后,強(qiáng)指針spInner就被析構(gòu)了,從上面的分析我們知道,強(qiáng)指針spInner析構(gòu)時(shí),會(huì)減少目標(biāo)對象的強(qiáng)引用計(jì)數(shù)值,因?yàn)榍懊娴玫降膹?qiáng)引用計(jì)數(shù)值為1,這里減1后,就變?yōu)?了,又由于這個(gè)StrongClass對象的生命周期只受強(qiáng)引用計(jì)數(shù)控制,因此,這個(gè)StrongClass對象就被delete了,這一點(diǎn)可以從后面的輸出(“Destory StrongClass Object.”)以及試圖把弱指針wpOut提升為強(qiáng)指針時(shí)得到的對象指針為0x0得到驗(yàn)證。

執(zhí)行TestWeakClass函數(shù)的輸出為:

Test Weak Class: Construct WeakClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. ----------------------- ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- spOut: 0xa528. Destory WeakClass Object.

TestWeakClass函數(shù)和TestStrongClass函數(shù)的執(zhí)行過程基本一樣,所不同的是當(dāng)程序跳出大括號之后,雖然這個(gè)WeakClass對象的強(qiáng)引用計(jì)數(shù)值已經(jīng)為0,但是由于它的生命周期同時(shí)受強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)控制,而這時(shí)它的弱引用計(jì)數(shù)值大于0,因此,這個(gè)WeakClass對象不會(huì)被delete掉,這一點(diǎn)可以從后面試圖把弱批針wpOut提升為強(qiáng)指針時(shí)得到的對象指針不為0得到驗(yàn)證。

執(zhí)行TestForeverClass函數(shù)的輸出來:

Test Froever Class: Construct ForeverClass Object. ----------------------- Strong Ref Count: 0. Weak Ref Count: 1. ----------------------- ----------------------- Strong Ref Count: 1. Weak Ref Count: 2. -----------------------

當(dāng)執(zhí)行完TestForeverClass函數(shù)返回到main函數(shù)的輸出來:

----------------------- Strong Ref Count: 0. Weak Ref Count: 0. ----------------------- Destory ForeverClass Object.

這里我們可以看出,雖然這個(gè)ForeverClass對象的強(qiáng)引用計(jì)數(shù)和弱引用計(jì)數(shù)值均為0了,但是它不自動(dòng)被delete掉,雖然由我們手動(dòng)地delete這個(gè)對象,它才會(huì)被析構(gòu),這是因?yàn)檫@個(gè)ForeverClass對象的生命周期是既不受強(qiáng)引用計(jì)數(shù)值控制,也不會(huì)弱引用計(jì)數(shù)值控制。

這樣,從TestStrongClass、TestWeakClass和TestForeverClass這三個(gè)函數(shù)的輸出就可以驗(yàn)證了我們上面對Android系統(tǒng)的強(qiáng)指針和弱指針的實(shí)現(xiàn)原理的分析。

6. 強(qiáng)弱指針的對比

  • 通過類圖可以發(fā)現(xiàn),強(qiáng)指針實(shí)現(xiàn)了 “.” “->” 操作符的重載,因此sp 可以直接方位類成員,而wp 卻不能,
  • 但是wp 可以轉(zhuǎn)化為sp

至此,Android系統(tǒng)的智能指針(輕量級指針、強(qiáng)指針和弱指針)的實(shí)現(xiàn)原理就分析完成了,它實(shí)現(xiàn)得很小巧但是很精致,希望讀者可以通過實(shí)際操作細(xì)細(xì)體會(huì)一下。

轉(zhuǎn)載于:https://www.cnblogs.com/linhaostudy/p/9507896.html

總結(jié)

以上是生活随笔為你收集整理的Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

精品久久久久久亚洲 | 极品美女被弄高潮视频网站 | 精品视频网站 | 久久99精品国产99久久6尤 | 九九热精品视频在线观看 | 六月色播| 亚洲精品动漫久久久久 | 美女视频一区 | 在线有码中文 | 亚洲精品久久久久中文字幕二区 | 久久精品一区二区三区四区 | 免费观看丰满少妇做爰 | 色婷婷亚洲| 午夜黄色一级片 | 狠狠色丁香婷婷综合 | 国产精品久久久久久久久久免费 | 国产成人精品一区二区 | 天天色 天天 | 日韩免费观看视频 | 在线观看一级片 | 久久久久久电影 | 亚洲成a人片在线www | 日韩视频免费在线 | 精品国模一区二区 | 夜夜骑首页 | 国产视频一区二区在线观看 | 久久99精品国产麻豆婷婷 | 激情偷乱人伦小说视频在线观看 | 中文字幕二区在线观看 | 国产精品成人免费 | 久久久精品 一区二区三区 国产99视频在线观看 | 国产成人一区二区在线观看 | 欧美日韩伦理一区 | 一本一本久久a久久 | 2019久久精品 | 久久久久久高清 | 日韩电影在线观看一区二区 | 在线а√天堂中文官网 | 国精产品999国精产品视频 | 天天干天天爽 | 日本在线观看视频一区 | 亚洲日本欧美 | 亚洲国产精彩中文乱码av | av高清免费在线 | 久久久91精品国产一区二区精品 | 国内精品久久久久久久久久清纯 | 免费观看成人网 | 亚洲aⅴ免费在线观看 | 国产精品免费大片视频 | 高清久久久 | 国产精品中文字幕在线 | 久久人人97超碰精品888 | zzijzzij亚洲日本少妇熟睡 | 日韩精品一区二 | 香蕉视频在线免费看 | 亚洲精品视频网站在线观看 | 日本xxxx.com| 欧美日韩电影在线播放 | www色片 | 五月天婷婷狠狠 | 日本久热 | 在线观看久久 | 4438全国亚洲精品观看视频 | 婷婷精品国产一区二区三区日韩 | 人人玩人人爽 | 成人网看片 | 国产精品久久久久永久免费看 | 色妞色视频一区二区三区四区 | 婷婷色中文字幕 | av色综合网 | 黄色一级免费网站 | 亚洲黄色av网址 | 激情片av | av免费线看 | 亚洲国产三级在线 | 欧美a级免费视频 | 色老板在线视频 | 五月天综合激情 | 日日躁你夜夜躁你av蜜 | 九九视频在线观看视频6 | 国产黄大片 | 女人高潮特级毛片 | 国产精品精品国产婷婷这里av | av播放在线 | 九色视频自拍 | 久久艹人人 | 婷婷综合网 | 色视频网站在线观看一=区 a视频免费在线观看 | 婷婷开心久久网 | 日本女人在线观看 | 视频二区| 91精品视频导航 | 天天舔天天搞 | 91精品国产成人www | 国产成人亚洲在线观看 | 国产免费av一区二区三区 | 久草男人天堂 | 中文字幕日韩无 | 国产精品字幕 | 国产精品亚洲视频 | 探花国产在线 | 久久免费99精品久久久久久 | 国产精品一区二区麻豆 | 99久久精品国产欧美主题曲 | 中文综合在线 | 999久久久免费精品国产 | 国产伦理一区二区三区 | 国产午夜精品久久久久久久久久 | 麻豆视频在线免费观看 | 久久久久久福利 | 日韩最新中文字幕 | 成年人免费在线观看网站 | 国产精品成 | 欧美福利片在线观看 | 中文在线中文资源 | www视频在线观看 | 四虎影视精品永久在线观看 | 国产精品乱码一区二三区 | 国产免费av一区二区三区 | 一区二区精品久久 | 亚洲精品高清视频 | 91视频在线| 国产一级大片在线观看 | 四虎影视8848dvd | 中文字幕一区二区三区视频 | 精品国产区在线 | 最近免费中文视频 | 午夜视频日本 | 亚洲精品白浆高清久久久久久 | 一区在线观看视频 | 九九热在线视频免费观看 | 国产日本在线观看 | 久久激情五月婷婷 | 在线免费高清视频 | 国产字幕在线播放 | 99国产高清| 国产麻豆电影在线观看 | 97香蕉久久超级碰碰高清版 | 一区二区不卡高清 | 国产91九色视频 | 狠狠操电影网 | 久草在线视频免费资源观看 | 久久精品国产免费看久久精品 | 国产视频999 | 一级黄色毛片 | 狠狠色丁香婷婷综合 | 99在线观看免费视频精品观看 | 国产高清av免费在线观看 | 香蕉免费 | 久久久久久久久久久免费视频 | 99精品黄色片免费大全 | 日韩美女黄色片 | 国产成人福利片 | 在线久草视频 | 午夜精品一区二区三区可下载 | 久久久国产精品一区二区中文 | 国产精品麻豆欧美日韩ww | 一区二区视频欧美 | 特级毛片网 | 免费色网站| 成年人电影免费看 | 五月婷婷狠狠 | 中文字幕 成人 | 免费在线观看国产精品 | 日本精品一区二区三区在线观看 | 国产精品一区久久久久 | 国产精品女人久久久 | 日韩69视频 | 波多野结衣动态图 | 人人揉人人揉人人揉人人揉97 | 日韩精品视频免费看 | 国产成人a亚洲精品v | 日本深夜福利视频 | 狠狠干五月天 | 国产欧美高清 | 欧美做受高潮电影o | 久久99久久99精品免费看小说 | 西西4444www大胆艺术 | 成年人在线电影 | 大型av综合网站 | 蜜桃传媒一区二区 | 欧美精品在线观看免费 | 久久夜av| 亚洲女人天堂成人av在线 | 日韩午夜精品 | 五月天激情综合网 | 一区二区三区免费在线观看视频 | 91色在线观看视频 | av资源在线看 | 韩国av免费在线观看 | 久久99久久精品国产 | 中文字幕在线观看一区二区三区 | 在线视频日韩精品 | 亚洲精品999 | 日韩在线观看高清 | 黄色av电影网 | 国产成人三级在线播放 | 日韩精品专区在线影院重磅 | 丁香综合激情 | 日本久久久久 | 日本不卡一区二区三区在线观看 | 日韩精品视频久久 | 国产专区在线 | 91精品国产乱码久久 | 日韩久久精品一区二区 | 国产一区二区成人 | 久久一级片 | 亚洲视频电影在线 | 天天操欧美 | www免费黄色 | 色妞久久福利网 | 久久黄色免费 | 亚洲自拍av在线 | 91麻豆精品91久久久久同性 | 国产精品黄色影片导航在线观看 | 中文字幕免费不卡视频 | 91热| 国产精品18久久久 | 国产九色视频在线观看 | 日韩视频一区二区 | 国产精品白浆视频 | 日韩精品一区二区在线 | 久久免费成人精品视频 | 涩涩网站在线播放 | 欧美一级电影免费观看 | 亚洲在线日韩 | 久久久高清免费视频 | 天天射网站 | 91精品一区在线观看 | 国产91精品看黄网站在线观看动漫 | 在线观看你懂的网站 | 国产免费视频一区二区裸体 | 久久国产免 | 9999在线视频| 四虎在线免费观看视频 | 国产乱老熟视频网88av | 国产黄色精品视频 | 在线观看国产日韩欧美 | 日韩欧美精品在线观看 | 深夜免费福利视频 | 1024在线看片 | 日韩精品视频在线观看免费 | 欧美精彩视频 | 91精品久| 中文字幕的 | 激情丁香月 | 美女网站黄在线观看 | 亚洲一二区精品 | 日韩免费b | 亚洲综合一区二区精品导航 | 国产女做a爱免费视频 | 日韩在线大片 | 色午夜| 欧美精品一二三 | 亚洲精选99 | 欧美人交a欧美精品 | 国产日韩视频在线观看 | 伊人射 | 五月婷婷激情综合网 | 天天综合日日夜夜 | 国产精品精品国产 | 日韩电影中文 | 国产一区二区视频在线 | 欧美亚洲精品在线观看 | 不卡av在线| 日韩av片无码一区二区不卡电影 | 欧美少妇18p | 国产精品一级视频 | 日韩区欠美精品av视频 | 免费h精品视频在线播放 | 丁香六月婷婷激情 | 免费人成在线观看网站 | 国产在线黄色 | 日日干激情五月 | 日韩电影中文字幕 | 91在线免费看片 | 日韩在线三级 | 国产精品久久久久久久久久东京 | 国产精久久久久久妇女av | 96国产在线 | 黄色成人毛片 | 国产九色在线播放九色 | 久久精品视频播放 | 91一区二区三区久久久久国产乱 | 国产精品久久久久久超碰 | av一区二区三区在线观看 | 色精品视频 | 日韩一三区 | 在线 视频 一区二区 | 青青河边草观看完整版高清 | 国产在线a不卡 | 高清国产午夜精品久久久久久 | 久久福利精品 | 黄色一级片视频 | 最新日韩在线观看视频 | 国产91精品看黄网站在线观看动漫 | 亚洲精品在线观 | 中文字幕免费久久 | 国产精品欧美一区二区 | 夜色.com | 国产色在线,com | 国产美女被啪进深处喷白浆视频 | 成人在线免费观看视视频 | 天天色天天 | 麻豆传媒视频在线 | 久久99国产综合精品 | 国产视频在线免费观看 | 国产精品一区二区中文字幕 | 在线播放日韩av | 国产精品色在线 | 色综合久久88色综合天天免费 | 国产成人精品av久久 | 免费在线观看视频一区 | 在线免费观看视频一区二区三区 | 日韩乱码在线 | 99综合影院在线 | 中文字幕成人在线观看 | 欧美精品亚洲精品 | www.超碰97.com | 在线成人性视频 | 亚洲综合视频在线播放 | 欧美巨乳网 | 精品久久久久久综合 | 麻豆免费视频 | 久草在线这里只有精品 | 国产亚洲精品久久久久久无几年桃 | 久久久久欠精品国产毛片国产毛生 | 免费在线播放av电影 | 久久免费观看少妇a级毛片 久久久久成人免费 | 亚洲国产精品一区二区久久,亚洲午夜 | 国产伦精品一区二区三区免费 | 国产一区在线视频 | av免费网站| 在线观看免费版高清版 | 亚洲综合激情网 | 伊人久久在线观看 | 成人久久亚洲 | av不卡免费看 | 欧美在线资源 | 精品久久久精品 | 综合五月婷婷 | 99在线热播精品免费 | 亚洲精品动漫在线 | 亚洲精品福利视频 | 久久久久国产成人免费精品免费 | 黄色avwww | 欧美精品久久99 | 亚洲激情 在线 | 日韩最新中文字幕 | 日本二区三区在线 | 99在线热播精品免费99热 | 亚洲乱码国产乱码精品天美传媒 | 精品在线一区二区三区 | 免费观看一区二区三区视频 | 亚洲人成免费网站 | 欧美在线free| 欧美另类xxxxx| 精品在线二区 | www.91av在线 | 久久国产精品免费一区 | 久久69精品久久久久久久电影好 | 国产精品亚洲片夜色在线 | 在线精品在线 | 亚洲欧美少妇 | 国产成人精品一区二区三区在线 | 一本一道久久a久久精品 | 亚洲国产精品视频在线观看 | 黄色软件视频大全免费下载 | 在线免费观看av网站 | 久久高清免费视频 | 国产专区视频 | 中文字幕日韩av | 麻豆成人精品视频 | 国产18精品乱码免费看 | 欧美激情第28页 | 99久久精品国产毛片 | 一区二区三区影院 | 99精品视频在线观看 | 亚洲精品看片 | av中文字幕免费在线观看 | 国产一区在线视频观看 | 日本性生活免费看 | 久久久www成人免费精品张筱雨 | 久久亚洲影院 | 婷婷丁香在线 | 亚洲自拍偷拍色图 | 人人爱人人射 | 综合网av | 午夜精品一区二区三区在线播放 | 在线视频观看你懂的 | 激情五月六月婷婷 | 日本久久久久久科技有限公司 | 国产精品久久久久久爽爽爽 | 欧美日韩亚洲在线 | 日韩欧美综合 | 国产精品久久久久影视 | 成人app在线播放 | 日韩三级精品 | 亚洲最快最全在线视频 | 在线视频a| 天天天天天天天操 | 91精品国产成人观看 | 成人av动漫在线观看 | 丁香综合激情 | 久插视频 | 有码中文在线 | 在线观看国产成人av片 | 国产资源在线观看 | 亚洲精品系列 | 精品一区二区三区久久 | 国产一区二区成人 | 日韩在线视频一区二区三区 | 亚洲成人av电影 | www.夜夜爽 | 天天在线视频色 | 少妇高潮流白浆在线观看 | 久久综合在线 | 狠狠色丁香久久婷婷综 | 中文十次啦 | av成人免费在线观看 | 婷婷www | 成人综合婷婷国产精品久久免费 | 五月婷婷在线观看视频 | 久久国产精品视频免费看 | 日韩电影在线视频 | 日韩在线观看视频网站 | 亚洲国产精品久久久久久 | 色网站在线看 | 亚洲高清视频在线观看 | 日韩电影在线视频 | 精品久久一二三区 | 毛片网站免费在线观看 | 国产99视频在线观看 | 手机在线免费av | 成人资源在线播放 | 国产精品高清在线观看 | 搡bbbb搡bbb视频 | 亚洲午夜av | 人人干在线 | av在线之家电影网站 | 97成人超碰| 亚洲精品美女久久17c | 在线中文视频 | 黄色毛片在线观看 | 免费黄a| 国产色网站 | 中文字幕一区二区三区四区视频 | 激情欧美日韩一区二区 | 在线岛国av | 国产区在线 | 色欲综合视频天天天 | 91黄色视屏| 欧美大片在线看免费观看 | 欧美日韩在线视频一区二区 | 91亚州 | 久久久www成人免费毛片 | 日本丰满少妇免费一区 | 99热亚洲精品 | 波多野结衣在线播放一区 | 欧美日韩视频免费看 | 国产片网站 | 久久精品激情 | 午夜久久成人 | 涩涩网站在线播放 | 综合色在线观看 | 日韩欧美在线观看一区二区三区 | 999久久久久久久久久久 | 国产精品一区二区三区久久久 | 久久久www成人免费精品 | 国产理论一区二区三区 | 久久天天拍 | 干天天 | 国产成人精品午夜在线播放 | 成x99人av在线www| 亚洲精品中文在线 | 不卡的av中文字幕 | 亚州性色| 在线免费观看黄色大片 | 又黄又爽又湿又无遮挡的在线视频 | 免费av在线网站 | 伊人久久在线观看 | 成人动漫一区二区三区 | 亚洲精品国产自产拍在线观看 | 亚洲一区精品二人人爽久久 | www.99av| 色婷婷亚洲精品 | 久艹视频免费观看 | 国产在线播放一区 | 亚洲综合黄色 | 国产精品久久久久久久久免费 | 夜夜夜影院| 亚洲一区二区观看 | 国产手机视频在线 | 中文字幕在线观看完整 | 亚洲精选久久 | 亚洲黄色片一级 | 69中文字幕 | 亚洲国产经典视频 | 亚洲精品视频在线观看免费 | 久久综合久久综合久久综合 | 久久99免费观看 | 天天射综合 | 99精品在线观看视频 | 九九久久久久久久久激情 | 粉嫩av一区二区三区入口 | 国产一级视频在线观看 | 亚洲九九九在线观看 | 91探花国产综合在线精品 | 少妇高潮冒白浆 | 91香蕉嫩草 | 黄色成人在线观看 | 国产主播大尺度精品福利免费 | 中文不卡视频在线 | 五月天中文字幕 | 精品久久久久国产免费第一页 | 18+视频网站链接 | 国产精品毛片一区二区在线 | 久久久在线 | 五月天丁香亚洲 | 日韩二区三区在线观看 | 国产又粗又硬又爽的视频 | 免费看搞黄视频网站 | 亚洲精品日韩在线观看 | 奇米影视在线99精品 | 久久婷婷视频 | 日日夜夜精品网站 | 午夜美女网站 | 综合色久 | 91视频链接| 成人在线观看免费 | 日韩成人在线免费观看 | 美女久久一区 | 在线a视频免费观看 | 超碰99在线 | 96av在线 | 最新国产精品拍自在线播放 | 久久久麻豆精品一区二区 | 国产精品一区二区三区免费视频 | 久久噜噜少妇网站 | 丁香午夜 | 日本一区二区三区视频在线播放 | 在线观看免费视频你懂的 | 狠狠狠色丁香婷婷综合久久88 | 国产一级免费观看 | 久草在线视频在线观看 | 不卡国产在线 | 91亚洲国产 | 青春草视频在线播放 | av丝袜在线 | 国产色综合天天综合网 | 黄色软件视频大全免费下载 | 亚洲精品高清在线观看 | 日韩电影在线观看一区二区 | 天天av在线播放 | 91精品在线观看视频 | 久久婷婷一区二区三区 | 成人蜜桃网 | 欧美色图亚洲图片 | 午夜三级在线 | 亚洲一区二区三区四区在线视频 | 91精品视频免费 | 日韩中文字幕免费在线观看 | 91色偷偷 | 日韩欧美在线免费 | 日韩乱理 | 欧美小视频在线观看 | 国产精品一区二区在线观看免费 | 国产日韩在线一区 | 91在线一区 | a成人v在线| 五月天激情电影 | 久久久精品国产一区二区三区 | 草久久久久久 | 亚洲91精品在线观看 | 黄色1级大片 | 欧美日韩中文在线视频 | 激情五月亚洲 | 色九九视频 | 99久久www| 伊人官网 | 狠狠的日日 | 国产视频一区二区在线播放 | 亚洲高清免费在线 | 亚洲精品黄色在线观看 | 精品一区二区三区久久久 | 久久精品在线免费观看 | 久久官网 | 久久久久久国产精品999 | 国产高清视频免费最新在线 | 国产中文a | 久久草 | 久久成人国产 | 中文字幕亚洲五码 | av在线色 | 999热线在线观看 | 成人影视片 | 国产精品国产亚洲精品看不卡15 | 中文av在线天堂 | 日本黄色大片免费 | 久久久午夜精品福利内容 | 果冻av在线 | 成人啪啪18免费游戏链接 | 亚洲国产欧美在线人成大黄瓜 | 日韩高清在线一区二区三区 | 国产美女精品视频免费观看 | 一区二区三区免费看 | 97精品久久| 爱情影院aqdy鲁丝片二区 | 又粗又长又大又爽又黄少妇毛片 | 成年人看片网站 | 久久久久久福利 | 夜夜操天天摸 | 久久99热精品这里久久精品 | 久99久中文字幕在线 | av在线免费网站 | 亚洲国产精品激情在线观看 | www.色午夜 | 欧美性久久久久久 | 97精品超碰一区二区三区 | 日韩在线视频免费看 | 91免费的视频在线播放 | 国产一级片一区二区三区 | 国产精品久久久久久久久久久久久久 | 青草视频网 | 亚洲丁香日韩 | 免费一级黄色 | 亚洲午夜久久久久久久久 | 成年人天堂com | 免费黄在线看 | 亚洲天堂在线观看完整版 | 99这里都是精品 | 亚洲丁香日韩 | 久久国产精品久久w女人spa | 免费视频你懂的 | 人人草在线视频 | 草久在线观看 | 91成年人视频 | 国产精品久久一区二区三区, | mm1313亚洲精品国产 | 99国产精品一区二区 | 亚洲欧美日韩在线看 | 亚洲精品国产精品国产 | 欧美在线视频第一页 | 五月婷婷视频在线观看 | 亚洲国产精品99久久久久久久久 | 国产一区二区电影在线观看 | 国产精品久久一 | 亚洲久草视频 | 久久激五月天综合精品 | 美女免费视频观看网站 | 午夜精品一区二区三区在线 | 日韩高清免费观看 | 四虎天堂| 亚洲精品网址在线观看 | 国产九色在线播放九色 | 91久久奴性调教 | 国产麻豆果冻传媒在线观看 | 日韩久久精品 | 婷婷av色综合| 碰超人人| 成人黄色大片网站 | 亚洲国产成人在线播放 | 久久高清毛片 | 激情久久影院 | 亚洲日本韩国一区二区 | 麻豆视频国产精品 | 美女网站色免费 | 亚洲精品国产精品乱码在线观看 | 欧美日韩国产成人 | 日日日天天天 | 三级黄色三级 | 美女国产在线 | 亚洲精品美女免费 | 激情网五月天 | 草久久影院 | 最近中文字幕 | 黄色成人毛片 | 99c视频高清免费观看 | 成年人免费在线观看网站 | 久久国产精品99久久人人澡 | 欧美 日韩 性 | 成人在线免费视频观看 | 国产麻豆精品久久一二三 | 视频国产精品 | 成年人电影免费在线观看 | 日本激情动作片免费看 | 色.com| www.午夜| 五月丁色| 免费视频黄| 在线免费看片 | 00av视频 | 欧美黄在线 | 国产 欧美 日产久久 | 青草视频在线 | 久久毛片网站 | 激情图片久久 | 黄色大片视频网站 | 天天色婷婷 | 99久久精品免费 | 欧美一区二区免费在线观看 | 久久久久久久99 | 日韩欧美国产激情在线播放 | 日韩高清免费电影 | 欧美韩日视频 | 成人黄视频 | www.色com| 久久久久久久久久久国产精品 | 免费a视频 | 97电影网站 | 天天噜天天色 | 欧美三级在线播放 | 丝袜美女在线观看 | 91热精品 | 99精品免费视频 | 久热爱| 婷婷六月天丁香 | 人成午夜视频 | 国产成人a亚洲精品v | 狠狠操夜夜操 | 天天操天天操天天爽 | 国产精品成人一区 | 人人舔人人爽 | 亚洲一级久久 | www在线观看视频 | 狠狠88综合久久久久综合网 | 欧美一区二视频在线免费观看 | 欧美性视频网站 | 久久久久久久久久久免费视频 | 在线亚洲日本 | 国产精品久久久久久久久久三级 | 五月天亚洲激情 | 久久99久久99久久 | 麻豆视频在线免费观看 | 国产主播大尺度精品福利免费 | 亚洲精品日韩一区二区电影 | 激情视频区 | 97在线看 | 色天天综合久久久久综合片 | 日本精品一区二区 | 国内精品久久久久影院优 | 成人h电影 | 免费观看一区 | 亚洲 欧美变态 另类 综合 | 丁香六月国产 | 白丝av在线| 亚洲黄色免费在线 | 国内精品久久久久久中文字幕 | 久久综合中文字幕 | 五月天婷婷综合 | h视频日本 | 免费看成人av | 人人射网站 | 国产精品久久久久久久久久三级 | 9999在线 | 国产精品成人自产拍在线观看 | 久久久久亚洲精品中文字幕 | 播五月综合| 久久成人综合 | 国产日韩精品在线观看 | 一区二区三区在线影院 | 色婷婷福利| av超碰在线 | 国产精品高清在线 | 人人澡人人草 | 国产精品18久久久久久首页狼 | 国产在线播放一区二区三区 | 免费日韩一区 | 91成人在线网站 | 日韩精品你懂的 | 久久久久五月天 | 在线看欧美 | www.香蕉视频 | 国产精品18久久久久白浆 | 国产成人精品网站 | 永久免费的av电影 | 8x8x在线观看视频 | 国产午夜在线 | 狠狠的干狠狠的操 | 国产亚洲精品久久网站 | 在线免费黄| 91在线看| 免费看精品久久片 | 伊人婷婷网 | 美女很黄免费网站 | 欧美成人精品欧美一级乱黄 | 国产精品精品国产婷婷这里av | 日韩久久久久久久久久 | 久久伊人免费视频 | 欧美日韩视频 | 国产中文字幕在线 | 婷婷中文字幕在线观看 | 免费日韩一区二区三区 | 日本精品免费看 | 五月婷婷丁香 | 久久精品一区二区三区中文字幕 | 精品国产三级 | 日韩av在线一区二区 | 91人人插| 成人在线一区二区 | 日本最新高清不卡中文字幕 | 亚洲爱av | 美女免费视频观看网站 | 久久精品三 | 综合久久一本 | 亚洲激情在线观看 | 色噜噜日韩精品一区二区三区视频 | 久久免费的精品国产v∧ | 九九精品视频在线观看 | 国产精品一区二区三区电影 | 韩国av不卡 | 欧美a√大片 | 在线91播放 | 国产精品自拍在线 | 久久午夜电影院 | 性色视频在线 | 97精品国产手机 | 少妇bbbb搡bbbb搡bbbb | 黄色成人免费电影 | 国产中文自拍 | 亚洲一区二区视频在线 | 97av在线视频免费播放 | 天天噜天天色 | 国产精品av免费在线观看 | 欧美一区二区在线免费看 | 青青河边草免费直播 | www色av| 九九爱免费视频在线观看 | 手机在线中文字幕 | 制服丝袜天堂 | 国产精品久久久一区二区 | 在线观看日韩精品视频 | 精品亚洲视频在线观看 | 国产不卡在线看 | 973理论片235影院9 | 男女全黄一级一级高潮免费看 | 日韩一区二区免费视频 | 99免费在线观看 | 福利视频一区二区 | 欧美日韩高清一区二区三区 | 国产一级淫片免费看 | 国内久久精品视频 | 免费久久视频 | 色网站在线免费观看 | 99视频一区二区 | 天天操综合网站 | 久久久久免费网 | 国产福利一区二区三区视频 | 夜又临在线观看 | 国产精品久久久久久久久岛 | 国产精品美女久久 | 久久成人在线 | 国产九九九九九 | 日韩电影在线一区 | 亚洲成人黄色在线观看 | 国产成人综合精品 | 午夜国产一区二区 | 国产偷国产偷亚洲清高 | 丁香婷婷激情 | 久久久这里有精品 | 日本大尺码专区mv | 91爱爱免费观看 | 最近免费中文字幕mv在线视频3 | 久久综合久久综合这里只有精品 | 欧美日在线观看 | 日韩三区在线 | 天天爽人人爽 | 亚洲视频精品 | 日韩中文字幕免费视频 | 国产精品久久久毛片 | 国产视频一区二区在线播放 | 精品一二区 | 国产视频一区二区在线 | 久久久亚洲电影 | 久久免费看av| 国产麻豆视频 | 久久成人福利 | 久久久久99精品国产片 | 99看视频在线观看 | 日免费视频 | av黄色在线观看 | 日韩小视频 | 国产中文字幕第一页 | 欧美日本在线视频 | 狠狠狠狠狠狠操 | 91精品国自产拍天天拍 | 91私密视频| av综合站 | 天天射天天舔天天干 | 日韩av免费在线电影 | 亚洲人成综合 | 欧美极品少妇xbxb性爽爽视频 | 亚洲成av人影院 | 欧美日韩精品在线视频 | 日本资源中文字幕在线 | 久久久受www免费人成 | 午夜美女网站 | 国产一区二区手机在线观看 | 日韩免费在线观看视频 | free. 性欧美.com | 国产在线a不卡 | 色婷婷免费视频 | 麻豆成人在线观看 | 国产成人av电影在线 | 又黄又刺激 | 日本久久久影视 | 密桃av在线 | 久射网| 91网在线 | 日日夜夜天天干 | 国产经典av | 国产99久久久精品 | 国产麻豆电影 | 国产精品毛片一区视频播不卡 | 69热国产视频 | 97国产一区 | 亚洲精品综合欧美二区变态 | 久久久久久网 | 黄色片免费电影 | 日韩精品视频一二三 | 六月天色婷婷 | 欧美大片mv免费 | 国产香蕉97碰碰碰视频在线观看 | 久久成人国产精品免费软件 | 色婷婷av一区二 | 国产精品免费观看在线 | 中文字幕一区二区三区四区在线视频 | 久久精品中文字幕少妇 | 免费观看黄 | 最新中文字幕视频 | 欧美性极品xxxx娇小 | 成年人在线看视频 | 欧美日韩一区二区三区在线观看视频 | 精品国产伦一区二区三区免费 | 黄色av一区二区三区 | 日日干精品 | 国产精品九九视频 | 五月婷婷在线播放 | 欧美精品在线视频观看 | 黄色大片日本 | 精品国产精品国产偷麻豆 | 国产精品高清在线 | 免费在线观看污网站 | 国产精品久久久久久久免费观看 | 色婷婷综合久久久中文字幕 | 成人高清av在线 | 亚洲国产精品电影 | 五月综合色 | 国产一级做a爱片久久毛片a | 最近最新最好看中文视频 | 免费看的毛片 | 色欲综合视频天天天 | 69av在线播放 | www.香蕉| 欧美一性一交一乱 | 免费三级av | 免费看一级片 | 国产99区 | 天天干天天操天天射 | 四虎成人精品永久免费av九九 | 国产三级精品在线 | 色婷婷骚婷婷 | 四虎永久视频 | 美女网站视频一区 | 精品视频| 亚洲春色成人 | 久久精品麻豆 | 欧美成年网站 | .国产精品成人自产拍在线观看6 | 亚洲激精日韩激精欧美精品 | 国产精品久久久久久久免费 | 亚洲激情五月 | 天天操夜夜操国产精品 | 天天操综合 | 日韩免费中文 | 91麻豆精品国产91久久久无需广告 | 亚洲精品黄色在线观看 | 欧洲精品视频一区二区 | 91精品专区| 国产精品久久久久久久久久东京 | 激情在线网址 | 久久久久久久久网站 | 亚洲最大激情中文字幕 | 久久免费看av | 久久久久久久久久久福利 | 手机av片 | 夜色资源站国产www在线视频 | 在线视频 成人 | 伊人开心激情 | 一级淫片在线观看 | 国产糖心vlog在线观看 | 天天爱天天操天天射 | av国产在线观看 | 黄色av影院 | 91桃色免费视频 | 久久高清毛片 | 在线免费观看国产精品 | 日韩av视屏在线观看 |