• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計模式} {C#基礎(chǔ)}

            .Net內(nèi)存管理和垃圾回收

            .NET 框架的垃圾回收器管理應(yīng)用程序的內(nèi)存分配和釋放。每次您使用 new 運算符創(chuàng)建對象時,運行庫都從托管堆為該對象分配內(nèi)存。只要托管堆中有地址空間可用,運行庫就會繼續(xù)為新對象分配空間。但是,內(nèi)存不是無限大的。最終,垃圾回收器必須執(zhí)行回收以釋放一些內(nèi)存。垃圾回收器優(yōu)化引擎根據(jù)正在進行的分配情況確定執(zhí)行回收的最佳時間。當(dāng)垃圾回收器執(zhí)行回收時,它檢查托管堆中不再被應(yīng)用程序使用的對象并執(zhí)行必要的操作來回收它們占用的內(nèi)存。

            開發(fā)人員在內(nèi)存管理方面的背景
            根據(jù)您開發(fā)背景的不同,您在內(nèi)存管理方面的經(jīng)驗也會有所不同。在某些情況下,您可能需要讓您的編程習(xí)慣來適應(yīng)公共語言運行庫提供的自動內(nèi)存管理。

            COM 開發(fā)人員
            COM 開發(fā)人員習(xí)慣于將實現(xiàn)引用計數(shù)作為一個手動的內(nèi)存管理技術(shù)。每次引用一個對象,計數(shù)器就遞增。如果對對象的引用超出了范圍,計數(shù)器就遞減。當(dāng)對象的引用計數(shù)達到零時,對象被終止并釋放其內(nèi)存。

            引用計數(shù)方案會引發(fā)許多調(diào)試錯誤。如果未能嚴格地按照引用計數(shù)的規(guī)則進行操作,對象可能被過早釋放或者未引用的對象積存在內(nèi)存中。循環(huán)引用也是常見的問題根源。循環(huán)引用出現(xiàn)在子對象引用父對象,而父對象又引用子對象時。這種情況使兩個對象都不能被釋放或銷毀。唯一的解決方案就是讓父對象和子對象都遵守一個固定的使用和銷毀模式,例如總是先由父對象刪除子對象。

            當(dāng)使用托管語言開發(fā)應(yīng)用程序時,運行庫的垃圾回收器免除了對引用進行計數(shù)的需要,因此也就避免了由這種手動管理內(nèi)存方案引發(fā)的錯誤。

            C++ 開發(fā)人員
            C++ 開發(fā)人員熟悉與手動內(nèi)存管理相關(guān)的任務(wù)。在 C++ 中,當(dāng)您使用 new 運算符為對象分配內(nèi)存時,您必須使用 delete 運算符釋放對象的內(nèi)存。這可能導(dǎo)致多種錯誤,例如忘記釋放對象、引起內(nèi)存泄漏或試圖訪問已被釋放的對象的內(nèi)存。

            當(dāng)使用 C++ 的托管擴展或其他托管語言開發(fā)應(yīng)用程序時,您就不必使用 delete 運算符釋放對象了。垃圾回收器在當(dāng)對象不再被應(yīng)用程序使用時自動為您完成這些操作。

            考慮到手動管理短期對象內(nèi)存的相關(guān)成本,C++ 開發(fā)人員可能習(xí)慣于避免使用這些對象。對于兩次回收間創(chuàng)建的然后又不再使用的托管短期對象,分配和釋放內(nèi)存的成本非常低。在 .NET 框架中,實際上已經(jīng)對垃圾回收器進行了優(yōu)化來管理具有較短生存期的對象。當(dāng)開發(fā)托管應(yīng)用程序時,在短期對象可以簡化代碼的情況下使用它們是非常合適的。

            Visual Basic 開發(fā)人員
            Visual Basic 開發(fā)人員習(xí)慣于自動內(nèi)存管理。您熟悉的編程慣例將應(yīng)用于您在 .NET 框架中創(chuàng)建的大多數(shù)托管對象。但是,當(dāng)創(chuàng)建或使用封裝非托管資源的對象時,您應(yīng)該特別注意使用 Dispose 方法的推薦設(shè)計模式。

            .NET 框架支持的托管語言比此處介紹的還要多。不管您使用哪一種托管語言,.NET 框架的垃圾回收器都提供自動內(nèi)存管理。它為托管對象分配和釋放內(nèi)存,并在必要時執(zhí)行 Finalize 方法和析構(gòu)函數(shù)來適當(dāng)?shù)厍謇矸峭泄苜Y源。自動內(nèi)存管理通過消除手動內(nèi)存管理方案引起的常見問題簡化了開發(fā)。

            Finalize 方法和析構(gòu)函數(shù)
            對于您的應(yīng)用程序創(chuàng)建的大多數(shù)對象,可以依靠 .NET 框架的垃圾回收器隱式地執(zhí)行所有必要的內(nèi)存管理任務(wù)。但是,在您創(chuàng)建封裝非托管資源的對象時,當(dāng)您在應(yīng)用程序中使用完這些非托管資源之后,您必須顯式地釋放它們。最常見的一類非托管資源就是包裝操作系統(tǒng)資源的對象,例如文件、窗口或網(wǎng)絡(luò)連接。雖然垃圾回收器可以跟蹤封裝非托管資源的對象的生存期,但它不了解具體如何清理這些資源。對于這些類型的對象,.NET 框架提供 Object.Finalize 方法,它允許對象在垃圾回收器回收該對象使用的內(nèi)存適當(dāng)清理其非托管資源默認情況下,F(xiàn)inalize 方法不執(zhí)行任何操作。如果您要讓垃圾回收器在回收對象的內(nèi)存之前對對象執(zhí)行清理操作,您必須在類中重寫 Finalize 方法。當(dāng)使用 C# 和 C++ 的托管擴展以外的編程語言進行開發(fā)時,您可以實現(xiàn) Finalize 方法。C# 和托管擴展提供析構(gòu)函數(shù)作為編寫終止代碼的簡化機制。析構(gòu)函數(shù)自動生成 Finalize 方法和對基類的 Finalize 方法的調(diào)用。在 C# 和托管擴展編程語言中,您必須為終止代碼使用析構(gòu)函數(shù)語法。

            垃圾回收器使用名為“終止隊列”的內(nèi)部結(jié)構(gòu)跟蹤具有 Finalize 方法的對象。每次您的應(yīng)用程序創(chuàng)建具有 Finalize 方法的對象時,垃圾回收器都在終止隊列中放置一個指向該對象的項。托管堆中所有需要在垃圾回收器回收其內(nèi)存之前調(diào)用它們的終止代碼的對象都在終止隊列中含有項。

            實現(xiàn) Finalize 方法或析構(gòu)函數(shù)對性能可能會有負面影響,因此應(yīng)避免不必要地使用它們。用 Finalize 方法回收對象使用的內(nèi)存需要至少兩次垃圾回收。當(dāng)垃圾回收器執(zhí)行回收時,它只回收沒有終結(jié)器的不可訪問對象的內(nèi)存。這時,它不能回收具有終結(jié)器的不可訪問對象。它改為將這些對象的項從終止隊列中移除并將它們放置在標為準備終止的對象列表中。該列表中的項指向托管堆中準備被調(diào)用其終止代碼的對象。一個特殊的運行庫線程開始處于活動狀態(tài)并調(diào)用列表中對象的 Finalize 方法,然后將這些項從列表中移除。后來的垃圾回收將確定終止的對象確實是垃圾,因為標為準備終止對象的列表中的項不再指向它們。在后來的垃圾回收中,實際上回收了對象的內(nèi)存。

            清理非托管資源
            通過將對象的范圍限制為 protected,您可以防止應(yīng)用程序的用戶直接調(diào)用對象的 Finalize 方法。除此之外,我們強烈建議您不要直接從應(yīng)用程序代碼中調(diào)用非基類的類的 Finalize 方法為適當(dāng)處置非托管資源,建議您實現(xiàn)公共的 Dispose 或 Close 方法,這兩個方法執(zhí)行必要的對象清理代碼。IDisposable 接口為實現(xiàn)接口的資源類提供 Dispose method。因為 Dispose 方法是公共的,所以應(yīng)用程序的用戶可以直接調(diào)用該方法來釋放非托管資源占用的內(nèi)存。如果正確實現(xiàn)了 Dispose 方法,則 Finalize 方法(或者 C# 中的析構(gòu)函數(shù)或 C++ 的托管擴展)就成為避免在沒有調(diào)用 Dispose 方法的情況下清理資源的一種防護措施。

            實現(xiàn) Dispose 方法 [C#]
            類型的 Dispose 方法應(yīng)該釋放它擁有的所有資源。它還應(yīng)該通過調(diào)用其父類型的 Dispose 方法釋放其基類型擁有的所有資源。該父類型的 Dispose 方法應(yīng)該釋放它擁有的所有資源并同樣也調(diào)用其父類型的 Dispose 方法,從而在整個基類型層次結(jié)構(gòu)中傳播該模式。要確保始終正確地清理資源,Dispose 方法應(yīng)該可以被多次安全調(diào)用而不引發(fā)任何異常。

            Dispose 方法應(yīng)該為它處置的對象調(diào)用 GC.SuppressFinalize 方法。如果對象當(dāng)前在終止隊列中,GC.SuppressFinalize 防止其 Finalize 方法被調(diào)用。請記住,執(zhí)行 Finalize 方法會大大減損性能。如果您的 Dispose 方法已經(jīng)完成了清理對象的工作,那么垃圾回收器就不必調(diào)用對象的 Finalize 方法了。

            下面的代碼示例旨在闡釋如何為封裝了非托管資源的類實現(xiàn) Dispose 方法的一種可能的設(shè)計模式。因為該模式是在整個 .NET 框架中實現(xiàn)的,所以您可能會發(fā)現(xiàn)它十分便于使用。但是,這不是 Dispose 方法唯一可能的實現(xiàn)。

            資源類通常是從復(fù)雜的本機類或 API 派生的,而且必須進行相應(yīng)的自定義。使用這一代碼模式作為創(chuàng)建資源類的一個起始點,并根據(jù)封裝的資源提供必要的自定義。不能編譯該示例,也不能將其直接用于應(yīng)用程序。

            在此示例中,基類 BaseResource 實現(xiàn)可由類的用戶調(diào)用的公共 Dispose 方法。而該方法又調(diào)用 virtual Dispose(bool disposing) 方法(Visual Basic 中的虛 Dispose(作為布爾值處置))。根據(jù)調(diào)用方的標識傳遞 true 或 false。以虛 Dispose 方法為對象執(zhí)行適當(dāng)?shù)那謇泶a。

            Dispose(bool disposing) 以兩種截然不同的方案執(zhí)行。如果處置結(jié)果為 true,則該方法已由用戶的代碼直接調(diào)用或間接調(diào)用,并且可處置托管資源和非托管資源。如果處置結(jié)果為 false,則該方法已由運行庫從終結(jié)器內(nèi)部調(diào)用,并且只能處置非托管資源。因為終結(jié)器不會以任意特定的順序執(zhí)行,所以當(dāng)對象正在執(zhí)行其終止代碼時,不應(yīng)引用其他對象。如果正在執(zhí)行的終結(jié)器引用了另一個已經(jīng)終止的對象,則該正在執(zhí)行的終結(jié)器將失敗。

            基類提供的 Finalize 方法或析構(gòu)函數(shù)在未能調(diào)用 Dispose 的情況下充當(dāng)防護措施。Finalize 方法調(diào)用帶有參數(shù)的 Dispose 方法,同時傳遞 false。不應(yīng)在 Finalize 方法內(nèi)重新創(chuàng)建 Dispose 清理代碼。調(diào)用 Dispose(false) 可以優(yōu)化代碼的可讀性和可維護性。

            類 MyResourceWrapper 闡釋如何用 Dispose 從實現(xiàn)資源管理的類派生。MyResourceWrapper 重寫 virtual Dispose(bool disposing) 方法并為其創(chuàng)建的托管和非托管資源提供清理代碼。MyResourceWrapper 還對其基類 BaseResource 調(diào)用 Dispose 以確保其基類能夠適當(dāng)?shù)剡M行清理。請注意,派生類 MyResourceWrapper 沒有不帶參數(shù)的 Finalize 方法或 Dispose 方法,因為這兩個方法從基類 BaseResource 繼承它們。

            [C#]?
            // ?Design?pattern?for?the?base?class.?
            // ?By?implementing?IDisposable,?you?are?announcing?that?instances?
            // ?of?this?type?allocate?scarce?resources.?
            public ? class ?BaseResource:?IDisposable?
            {?
            // ?Pointer?to?an?external?unmanaged?resource.?
            private ?IntPtr?handle;?
            // ?Other?managed?resource?this?class?uses.?
            private ?Component?Components;?
            // ?Track?whether?Dispose?has?been?called.?
            private ? bool ?disposed? = ? false ;?

            // ?Constructor?for?the?BaseResource?Object.?
            public ?BaseResource()?
            {?
            // ?Insert?appropriate?constructor?code?here.?
            }
            ?

            // ?Implement?Idisposable.?
            // ?Do?not?make?this?method?virtual.?
            // ?A?derived?class?should?not?be?able?to?override?this?method.?
            public ? void ?Dispose()?
            {?
            Dispose(
            true );?
            // ?Take?yourself?off?of?the?Finalization?queue?
            // ?to?prevent?finalization?code?for?this?object?
            // ?from?executing?a?second?time.?
            GC.SuppressFinalize( this );?
            }
            ?

            // ?Dispose(bool?disposing)?executes?in?two?distinct?scenarios.?
            // ?If?disposing?equals?true,?the?method?has?been?called?directly?
            // ?or?indirectly?by?a?user's?code.?Managed?and?unmanaged?resources?
            // ?can?be?disposed.?
            // ?If?disposing?equals?false,?the?method?has?been?called?by?the?
            // ?runtime?from?inside?the?finalizer?and?you?should?not?reference?
            // ?other?objects.?Only?unmanaged?resources?can?be?disposed.?
            protected ? virtual ? void ?Dispose( bool ?disposing)?
            {?
            // ?Check?to?see?if?Dispose?has?already?been?called.?
            if ( ! this .disposed)?
            {?
            // ?If?disposing?equals?true,?dispose?all?managed?
            // ?and?unmanaged?resources.?
            if (disposing)?
            {?
            // ?Dispose?managed?resources.?
            Components.Dispose();?
            }
            ?
            // ?Release?unmanaged?resources.?If?disposing?is?false,?
            // ?only?the?following?code?is?executed.?
            CloseHandle(handle);?
            handle?
            = ?IntPtr.Zero;?
            // ?Note?that?this?is?not?thread?safe.?
            // ?Another?thread?could?start?disposing?the?object?
            // ?after?the?managed?resources?are?disposed,?
            // ?but?before?the?disposed?flag?is?set?to?true.?
            }
            ?
            disposed?
            = ? true ;?
            }
            ?

            // ?Use?C#?destructor?syntax?for?finalization?code.?
            // ?This?destructor?will?run?only?if?the?Dispose?method?
            // ?does?not?get?called.?
            // ?It?gives?your?base?class?the?opportunity?to?finalize.?
            // ?Do?not?provide?destructors?in?types?derived?from?this?class.?
            ~ BaseResource()?
            {?
            // ?Do?not?re-create?Dispose?clean-up?code?here.?
            // ?Calling?Dispose(false)is?optimal?in?terms?of?
            // ?readability?and?maintainability.?
            Dispose( false );?
            }
            ?

            // ?Allow?your?Dispose?method?to?be?called?multiple?times,?
            // ?but?throw?an?exception?if?the?object?has?been?disposed.?
            // ?Whenever?you?do?something?with?this?class,?
            // ?check?to?see?if?it?has?been?disposed.?
            public ? void ?DoSomething()?
            {?
            if ( this .disposed)?
            {?
            throw ? new ?ObjectDisposedException();?
            }
            ?
            }
            ?
            }
            ?

            // ?Design?pattern?for?a?derived?class.?
            // ?Note?that?this?derived?class?inherently?implements?the?
            // ?IDisposable?interface?because?it?is?implemented?in?the?base?class.?
            public ? class ?MyResourceWrapper:?BaseResource?
            {?
            // ?A?managed?resource?that?you?add?in?this?derived?class.?
            private ?ManagedResource?addedManaged;?
            // ?A?native?unmanaged?resource?that?you?add?in?this?derived?class.?
            private ?NativeResource?addedNative;?
            private ? bool ?disposed? = ? false ;?

            // ?Constructor?for?this?object.?
            public ?MyResourceWrapper()?
            {?
            // ?Insert?appropriate?constructor?code?here.?
            }
            ?

            protected ? override ? void ?Dispose( bool ?disposing)?
            {?
            if ( ! this .disposed)?
            {?
            try ?
            {?
            if (disposing)?
            {?
            // ?Release?the?managed?resources?you?added?in?
            // ?this?derived?class?here.?
            addedManaged.Dispose();?
            }
            ?
            // ?Release?the?native?unmanaged?resources?you?added?
            // ?in?this?derived?class?here.?
            CloseHandle(addedNative);?
            this .disposed? = ? true ;?
            }
            ?
            finally ?
            {?
            // ?Call?Dispose?on?your?base?class.?
            base .Dispose(disposing);?
            }
            ?
            }
            ?
            }
            ?
            }
            ?

            // ?This?derived?class?does?not?have?a?Finalize?method?
             對于finalize()方法的另一個問題是開發(fā)人員不知道什么時候它將被調(diào)用。它不像C++中的析構(gòu)函數(shù)在刪除一個對象時被調(diào)用。為了解決這個問題,在.Net中提供了一個接口IDisposable。微軟建議在實現(xiàn)帶有fianlize()方法的類的時侯按照下面的模式定義對象:


            public?class?Class1?:?IDisposable?
            {
             
            public?Class1()
             
            {
             }


             
            ~Class1?()
             
            {
              
            //垃圾回收器將調(diào)用該方法,因此參數(shù)需要為false。
              Dispose?(false);
             }


             
            //該方法定義在IDisposable接口中。
             public?void?Dispose?()
             
            {
              
            //該方法由程序調(diào)用,在調(diào)用該方法之后對象將被終結(jié)。
              
            //因為我們不希望垃圾回收器再次終結(jié)對象,因此需要從終結(jié)列表中去除該對象。
              GC.SuppressFinalize?(this);
              
            //因為是由程序調(diào)用該方法的,因此參數(shù)為true。
              Dispose?(true);
             }


             
            //所有與回收相關(guān)的工作都由該方法完成
             private?void?Dispose(bool?disposing)
             ??
            {
              
            lock(this)?//避免產(chǎn)生線程錯誤。
              {
               
            if?(disposing)
               
            {
                
            //需要程序員完成釋放對象占用的資源。
               }


              
            //對象將被垃圾回收器終結(jié)。在這里添加其它和清除對象相關(guān)的代碼。
             }

            }

            }




            現(xiàn)在我們了解了垃圾回收器工作的基本原理,接下來讓我們看一看垃圾回收器內(nèi)部是如何工作的。目前有很多種類型的垃圾回收器。微軟實現(xiàn)了一種生存期垃圾回收器(Generational Garbage Collector)。生存期垃圾回收器將內(nèi)存分為很多個托管堆,每一個托管堆對應(yīng)一種生存期等級。生存期垃圾回收器遵循著下面的原則:

              新生成的對象,其生存期越短;而對象生成時間越長的對象,其生存期也就越長。對于垃圾回收器來說,回收一部分對象總是比回收全部對象要快,因此垃圾回收器對于那些生存期短的對象回收的頻率要比生存期長的對象的回收頻率高。

              .Net中的垃圾回收器中目前有三個生存期等級:0,1和2。0、1、2等級對應(yīng)的托管堆的初始化大小分別是256K,2M和10M。垃圾回收器在發(fā)現(xiàn)改變大小能夠提高性能的話,會改變托管堆的大小。例如當(dāng)應(yīng)用程序初始化了許多小的對象,并且這些對象會被很快回收的話,垃圾回收器就會將0等級的托管堆變?yōu)?28K,并且提高回收的頻率。如果情況相反,垃圾回收器發(fā)現(xiàn)在0等級的托管堆中不能回收很多空間時,就會增加托管堆的大小。

            在應(yīng)用程序初始化的之前,所有等級的托管堆都是空的。當(dāng)對象被初始化的時候,他們會按照初始化的先后順序被放入等級為0的托管堆中。在托管堆中對象的存放是連續(xù)的,這樣使得托管堆存取對象的速度很快,因為托管對不必對內(nèi)存進行搜索。垃圾回收器中保存了一個指針指向托管堆中最后一個對象之后的內(nèi)存空間。圖一中顯示了一個包含四個對象的0等級的托管堆。


            圖一 包含四個對象的托管堆

            當(dāng)0等級托管堆被對象填滿后,例如候程序初始化了新的對象,使0等級托管堆的大小超過了256K,垃圾回收器會檢查托管堆中的所有對象,看是否有對象可以回收。當(dāng)開始回收操作時,如前面提到的,垃圾回收器會找出根節(jié)點和根節(jié)點直接或間接引用了的對象,然后將這些對象轉(zhuǎn)移到1等級托管堆中,并將0等級托管堆的指針移到最開始的位置以清除所有的對象。同時垃圾回收器會壓縮1等級托管堆以保證所有對象之間沒有內(nèi)存空隙。當(dāng)1等級托管堆滿了之后,會將對象轉(zhuǎn)移到2等級的托管堆。

              例如在圖一之后,垃圾回收器開始回收對象,假定D對象將被回收,同時程序創(chuàng)建了E和F對象。這時候托管堆中的對象如圖二所示。


            圖二 回收對象后的0等級和1等級托管堆

              然后程序創(chuàng)建了新的對象G和H,再一次觸發(fā)了垃圾回收器。對象E將被回收。這時候托管堆中的對象如圖三所示。



              生存期垃圾回收器的原則也有例外的情況。當(dāng)對象的大小超過84K時,對象會被放入"大對象區(qū)"。大對象區(qū)中的對象不會被垃圾回收器回收,也不會被壓縮。這樣做是為了強制垃圾回收器只能回收小對象以提高程序的性能。

              控制垃圾回收器

              在.Net框架中提供了很多方法使開發(fā)人員能夠直接控制垃圾回收器的行為。通過使用GC.Collect()或GC.Collect(int GenerationNumber)開發(fā)人員可以強制垃圾回收器對所有等級的托管堆進行回收操作。在大多數(shù)的情況下開發(fā)人員不需要干涉垃圾回收器的行為,但是有些情況下,例如當(dāng)程序進行了非常復(fù)雜的操作后希望確認內(nèi)存中的垃圾對象已經(jīng)被回收,就可以使用上面的方法。另一個方法是GC.WaitForPendingFinalizers(),它可以掛起當(dāng)前線程,直到處理完成器隊列的線程清空該隊列為止。

              使用垃圾回收器最好的方法就是跟蹤程序中定義的對象,在程序不需要它們的時候手動釋放它們。例如程序中的一個對象中有一個字符串屬性,該屬性會占用一定的內(nèi)存空間。當(dāng)該屬性不再被使用時,開發(fā)人員可以在程序中將其設(shè)定為null,這樣垃圾回收器就可以回收該字符串占用的空間。另外,如果開發(fā)人員確定不再使用某個對象時,需要同時確定沒有其它對象引用該對象,否則垃圾回收器不會回收該對象。

              另外值得一提的是finalize()方法應(yīng)該在較短的時間內(nèi)完成,這是因為垃圾回收器給finalize()方法限定了一個時間,如果finalize()方法在規(guī)定時間內(nèi)還沒有完成,垃圾回收器會終止運行finalize()方法的線程。在下面這些情況下程序會調(diào)用對象的finalize()方法:

               0等級垃圾回收器已滿

               程序調(diào)用了執(zhí)行垃圾回收的方法

               公共語言運行庫正在卸載一個應(yīng)用程序域

               公共語言運行庫正在被卸載

            posted on 2006-04-30 15:52 夢在天涯 閱讀(2268) 評論(0)  編輯 收藏 引用 所屬分類: C#/.NET

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1807563
            • 排名 - 5

            最新評論

            閱讀排行榜

            国产午夜精品理论片久久影视 | 精品水蜜桃久久久久久久| 婷婷久久久亚洲欧洲日产国码AV| 亚洲国产精品无码久久SM| 国内精品久久人妻互换| 91秦先生久久久久久久| 亚洲国产香蕉人人爽成AV片久久| 久久成人国产精品免费软件| 久久精品成人欧美大片| 99久久国产综合精品网成人影院| 亚洲国产成人精品91久久久| 久久久久亚洲AV无码专区体验| 99久久精品免费观看国产| 四虎国产精品成人免费久久| 精品久久久久久国产| 久久只有这里有精品4| 久久久九九有精品国产| 亚洲精品国产第一综合99久久| 韩国无遮挡三级久久| 国产偷久久久精品专区| 久久午夜福利电影| 2020最新久久久视精品爱| 久久国产热精品波多野结衣AV| 久久综合伊人77777| 香港aa三级久久三级| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 久久精品一区二区三区不卡| 久久精品国产精品亚洲精品| 国产精自产拍久久久久久蜜| 国产精品久久成人影院| 国内精品久久久久影院老司| 伊人久久大香线蕉影院95| 久久亚洲国产精品一区二区| 国产精品国色综合久久| 亚洲美日韩Av中文字幕无码久久久妻妇 | 久久受www免费人成_看片中文| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲中文字幕无码久久精品1| 久久久精品人妻无码专区不卡| 国产免费久久精品99久久| 国产伊人久久|