<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    so true

    心懷未來,開創(chuàng)未來!
    隨筆 - 160, 文章 - 0, 評(píng)論 - 40, 引用 - 0
    數(shù)據(jù)加載中……

    Linux slab 分配器剖析

    original link: https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/

    Linux slab 分配器剖析

    了解 Linux 內(nèi)存管理的方式

    M. Tim Jones, 顧問工程師, Emulex
    M. Tim Jones 是一名嵌入式軟件工程師,他是 GNU/Linux Application Programming、AI Application Programming 以及 BSD Sockets Programming from a Multilanguage Perspective 等書的作者。他的工程背景非常廣泛,從同步宇宙飛船的內(nèi)核開發(fā)到嵌入式架構(gòu)設(shè)計(jì),再到網(wǎng)絡(luò)協(xié)議的開發(fā)。Tim 是位于科羅拉多州 Longmont 的 Emulex Corp. 的一名顧問工程師。

    簡介: 良好的操作系統(tǒng)性能部分依賴于操作系統(tǒng)有效管理資源的能力。在過去,堆內(nèi)存管理器是實(shí)際的規(guī)范,但是其 性能會(huì)受到內(nèi)存碎片和內(nèi)存回收需求的影響。現(xiàn)在,Linux® 內(nèi)核使用了源自于 Solaris 的一種方法,但是這種方法在嵌入式系統(tǒng)中已經(jīng)使用了很長時(shí)間了,它是將內(nèi)存作為對(duì)象按照大小進(jìn)行分配。本文將探索 slab 分配器背后所采用的思想,并介紹這種方法提供的接口和用法。

    發(fā)布日期: 2010 年 9 月 20 日
    級(jí)別: 中級(jí)
    建議: 0 (添加評(píng)論)

    1 star2 stars3 stars4 stars5 stars 平均分 (共 1 個(gè)評(píng)分 )

    動(dòng)態(tài)內(nèi)存管理

    內(nèi)存管理的目標(biāo)是提供一種方法,為實(shí)現(xiàn)各種目的而在各個(gè)用戶之間實(shí)現(xiàn)內(nèi)存共享。內(nèi)存管理方法應(yīng)該實(shí)現(xiàn)以下兩個(gè)功能:

    • 最小化管理內(nèi)存所需的時(shí)間
    • 最大化用于一般應(yīng)用的可用內(nèi)存(最小化管理開銷)

    內(nèi)存管理實(shí)際上是一種關(guān)于權(quán)衡的零和游戲。您可以開發(fā)一種使用少量內(nèi)存進(jìn)行管理的算法,但是要花費(fèi)更多時(shí)間來管理可用內(nèi)存。也可以開發(fā)一個(gè)算法來有效地管理內(nèi)存,但卻要使用更多的內(nèi)存。最終,特定應(yīng)用程序的需求將促使對(duì)這種權(quán)衡作出選擇。

    每個(gè)內(nèi)存管理器都使用了一種基于堆的分配策略。在這種方法中,大塊內(nèi)存(稱為 )用來為用戶定義的目的提供內(nèi)存。當(dāng)用戶需要一塊內(nèi)存時(shí),就請(qǐng)求給自己分配一定大小的內(nèi)存。堆管理器會(huì)查看可用內(nèi)存的情況(使用特定算法)并返回一塊內(nèi)存。搜索過程中使用的一些算法有 first-fit(在堆中搜索到的第一個(gè)滿足請(qǐng)求的內(nèi)存塊 )和 best-fit(使用堆中滿足請(qǐng)求的最合適的內(nèi)存塊)。當(dāng)用戶使用完內(nèi)存后,就將內(nèi)存返回給堆。

    這種基于堆的分配策略的根本問題是碎片(fragmentation)。當(dāng)內(nèi)存塊被分配后,它們會(huì)以不同的順序在不同的時(shí)間返回。這樣會(huì)在堆中留下一些洞,需要花一些時(shí)間才能有效地管理空閑內(nèi)存。這種算法通常具有較高的內(nèi)存使用效率(分配需要的內(nèi)存),但是卻需要花費(fèi)更多時(shí)間來對(duì)堆進(jìn)行管理。

    另外一種方法稱為 buddy memory allocation, 是一種更快的內(nèi)存分配技術(shù),它將內(nèi)存劃分為 2 的冪次方個(gè)分區(qū),并使用 best-fit 方法來分配內(nèi)存請(qǐng)求。當(dāng)用戶釋放內(nèi)存時(shí),就會(huì)檢查 buddy 塊,查看其相鄰的內(nèi)存塊是否也已經(jīng)被釋放。如果是的話,將合并內(nèi)存塊以最小化內(nèi)存碎片。這個(gè)算法的時(shí)間效率更高,但是由于使用 best-fit 方法的緣故,會(huì)產(chǎn)生內(nèi)存浪費(fèi)。

    本文將著重介紹 Linux 內(nèi)核的內(nèi)存管理,尤其是 slab 分配提供的機(jī)制。

    slab 緩存

    Linux 所使用的 slab 分配器的基礎(chǔ)是 Jeff Bonwick 為 SunOS 操作系統(tǒng)首次引入的一種算法。Jeff 的分配器是圍繞對(duì)象緩存進(jìn)行的。在內(nèi)核中,會(huì)為有限的對(duì)象集(例如文件描述符和其他常見結(jié)構(gòu))分配大量內(nèi)存。Jeff 發(fā)現(xiàn)對(duì)內(nèi)核中普通對(duì)象進(jìn)行初始化所需的時(shí)間超過了對(duì)其進(jìn)行分配和釋放所需的時(shí)間。因此他的結(jié)論是不應(yīng)該將內(nèi)存釋放回一個(gè)全局的內(nèi)存池,而是將內(nèi)存保持為針 對(duì)特定目而初始化的狀態(tài)。例如,如果內(nèi)存被分配給了一個(gè)互斥鎖,那么只需在為互斥鎖首次分配內(nèi)存時(shí)執(zhí)行一次互斥鎖初始化函數(shù)(mutex_init)即可。后續(xù)的內(nèi)存分配不需要執(zhí)行這個(gè)初始化函數(shù),因?yàn)閺纳洗吾尫藕驼{(diào)用析構(gòu)之后,它已經(jīng)處于所需的狀態(tài)中了。

    Linux slab 分配器使用了這種思想和其他一些思想來構(gòu)建一個(gè)在空間和時(shí)間上都具有高效性的內(nèi)存分配器。

    圖 1 給出了 slab 結(jié)構(gòu)的高層組織結(jié)構(gòu)。在最高層是 cache_chain,這是一個(gè) slab 緩存的鏈接列表。這對(duì)于 best-fit 算法非常有用,可以用來查找最適合所需要的分配大小的緩存(遍歷列表)。cache_chain 的每個(gè)元素都是一個(gè) kmem_cache 結(jié)構(gòu)的引用(稱為一個(gè) cache)。它定義了一個(gè)要管理的給定大小的對(duì)象池。


    圖 1. slab 分配器的主要結(jié)構(gòu)
         圖  1. slab 分配器的主要結(jié)構(gòu)

    每個(gè)緩存都包含了一個(gè) slabs 列表,這是一段連續(xù)的內(nèi)存塊(通常都是頁面)。存在 3 種 slab:

    slabs_full
    完全分配的 slab
    slabs_partial
    部分分配的 slab
    slabs_empty
    空 slab,或者沒有對(duì)象被分配

    注意 slabs_empty 列表中的 slab 是進(jìn)行回收(reaping)的主要備選對(duì)象。正是通過此過程,slab 所使用的內(nèi)存被返回給操作系統(tǒng)供其他用戶使用。

    slab 列表中的每個(gè) slab 都是一個(gè)連續(xù)的內(nèi)存塊(一個(gè)或多個(gè)連續(xù)頁),它們被劃分成一個(gè)個(gè)對(duì)象。這些對(duì)象是從特定緩存中進(jìn)行分配和釋放的基本元素。注意 slab 是 slab 分配器進(jìn)行操作的最小分配單位,因此如果需要對(duì) slab 進(jìn)行擴(kuò)展,這也就是所擴(kuò)展的最小值。通常來說,每個(gè) slab 被分配為多個(gè)對(duì)象。

    由于對(duì)象是從 slab 中進(jìn)行分配和釋放的,因此單個(gè) slab 可以在 slab 列表之間進(jìn)行移動(dòng)。例如,當(dāng)一個(gè) slab 中的所有對(duì)象都被使用完時(shí),就從 slabs_partial 列表中移動(dòng)到 slabs_full 列表中。當(dāng)一個(gè) slab 完全被分配并且有對(duì)象被釋放后,就從 slabs_full 列表中移動(dòng)到 slabs_partial 列表中。當(dāng)所有對(duì)象都被釋放之后,就從 slabs_partial 列表移動(dòng)到 slabs_empty 列表中。

    slab 背后的動(dòng)機(jī)

    與 傳統(tǒng)的內(nèi)存管理模式相比, slab 緩存分配器提供了很多優(yōu)點(diǎn)。首先,內(nèi)核通常依賴于對(duì)小對(duì)象的分配,它們會(huì)在系統(tǒng)生命周期內(nèi)進(jìn)行無數(shù)次分配。slab 緩存分配器通過對(duì)類似大小的對(duì)象進(jìn)行緩存而提供這種功能,從而避免了常見的碎片問題。slab 分配器還支持通用對(duì)象的初始化,從而避免了為同一目而對(duì)一個(gè)對(duì)象重復(fù)進(jìn)行初始化。最后,slab 分配器還可以支持硬件緩存對(duì)齊和著色,這允許不同緩存中的對(duì)象占用相同的緩存行,從而提高緩存的利用率并獲得更好的性能。


    回頁首

    API 函數(shù)

    現(xiàn)在來看一下能夠創(chuàng)建新 slab 緩存、向緩存中增加內(nèi)存、銷毀緩存的應(yīng)用程序接口(API)以及 slab 中對(duì)對(duì)象進(jìn)行分配和釋放操作的函數(shù)。

    第一個(gè)步驟是創(chuàng)建 slab 緩存結(jié)構(gòu),您可以將其靜態(tài)創(chuàng)建為:

    struct struct kmem_cache *my_cachep;

    然后其他 slab 緩存函數(shù)將使用該引用進(jìn)行創(chuàng)建、刪除、分配等操作。kmem_cache 結(jié)構(gòu)包含了每個(gè)中央處理器單元(CPU)的數(shù)據(jù)、一組可調(diào)整的(可以通過 proc 文件系統(tǒng)訪問)參數(shù)、統(tǒng)計(jì)信息和管理 slab 緩存所必須的元素。

    kmem_cache_create

    內(nèi)核函數(shù) kmem_cache_create 用來創(chuàng)建一個(gè)新緩存。這通常是在內(nèi)核初始化時(shí)執(zhí)行的,或者在首次加載內(nèi)核模塊時(shí)執(zhí)行。其原型定義如下:

    struct kmem_cache *
    kmem_cache_create( const char *name, size_t size, size_t align,
    unsigned long flags;
    void (*ctor)(void*, struct kmem_cache *, unsigned long),
    void (*dtor)(void*, struct kmem_cache *, unsigned long));

    name 參數(shù)定義了緩存名稱,proc 文件系統(tǒng)(在 /proc/slabinfo 中)使用它標(biāo)識(shí)這個(gè)緩存。 size 參數(shù)指定了為這個(gè)緩存創(chuàng)建的對(duì)象的大小, align 參數(shù)定義了每個(gè)對(duì)象必需的對(duì)齊。 flags 參數(shù)指定了為緩存啟用的選項(xiàng)。這些標(biāo)志如表 1 所示。


    表 1. kmem_cache_create 的部分選項(xiàng)(在 flags 參數(shù)中指定)
    選項(xiàng)說明
    SLAB_RED_ZONE 在對(duì)象頭、尾插入標(biāo)志,用來支持對(duì)緩沖區(qū)溢出的檢查。
    SLAB_POISON 使用一種己知模式填充 slab,允許對(duì)緩存中的對(duì)象進(jìn)行監(jiān)視(對(duì)象屬對(duì)象所有,不過可以在外部進(jìn)行修改)。
    SLAB_HWCACHE_ALIGN 指定緩存對(duì)象必須與硬件緩存行對(duì)齊。

    ctordtor 參數(shù)定義了一個(gè)可選的對(duì)象構(gòu)造器和析構(gòu)器。構(gòu)造器和析構(gòu)器是用戶提供的回調(diào)函數(shù)。當(dāng)從緩存中分配新對(duì)象時(shí),可以通過構(gòu)造器進(jìn)行初始化。

    在創(chuàng)建緩存之后, kmem_cache_create 函數(shù)會(huì)返回對(duì)它的引用。注意這個(gè)函數(shù)并沒有向緩存分配任何內(nèi)存。相反,在試圖從緩存(最初為空)分配對(duì)象時(shí),refill 操作將內(nèi)存分配給它。當(dāng)所有對(duì)象都被使用掉時(shí),也可以通過相同的操作向緩存添加內(nèi)存。

    kmem_cache_destroy

    內(nèi)核函數(shù) kmem_cache_destroy 用來銷毀緩存。這個(gè)調(diào)用是由內(nèi)核模塊在被卸載時(shí)執(zhí)行的。在調(diào)用這個(gè)函數(shù)時(shí),緩存必須為空。

    void kmem_cache_destroy( struct kmem_cache *cachep );

    kmem_cache_alloc

    要從一個(gè)命名的緩存中分配一個(gè)對(duì)象,可以使用 kmem_cache_alloc 函數(shù)。調(diào)用者提供了從中分配對(duì)象的緩存以及一組標(biāo)志:

    void kmem_cache_alloc( struct kmem_cache *cachep, gfp_t flags );

    這個(gè)函數(shù)從緩存中返回一個(gè)對(duì)象。注意如果緩存目前為空,那么這個(gè)函數(shù)就會(huì)調(diào)用 cache_alloc_refill 向緩存中增加內(nèi)存。 kmem_cache_alloc 的 flags 選項(xiàng)與 kmalloc 的 flags 選項(xiàng)相同。表 2 給出了標(biāo)志選項(xiàng)的部分列表。


    表 2. kmem_cache_alloc 和 kmalloc 內(nèi)核函數(shù)的標(biāo)志選項(xiàng)
    標(biāo)志說明
    GFP_USER 為用戶分配內(nèi)存(這個(gè)調(diào)用可能會(huì)睡眠)。
    GFP_KERNEL 從內(nèi)核 RAM 中分配內(nèi)存(這個(gè)調(diào)用可能會(huì)睡眠)。
    GFP_ATOMIC 使該調(diào)用強(qiáng)制處于非睡眠狀態(tài)(對(duì)中斷處理程序非常有用)。
    GFP_HIGHUSER 從高端內(nèi)存中分配內(nèi)存。

    kmem_cache_zalloc

    內(nèi)核函數(shù) kmem_cache_zallockmem_cache_alloc 類似,只不過它對(duì)對(duì)象執(zhí)行 memset 操作,用來在將對(duì)象返回調(diào)用者之前對(duì)其進(jìn)行清除操作。

    kmem_cache_free

    要將一個(gè)對(duì)象釋放回 slab,可以使用 kmem_cache_free。調(diào)用者提供了緩存引用和要釋放的對(duì)象。

    void kmem_cache_free( struct kmem_cache *cachep, void *objp );

    kmalloc 和 kfree

    內(nèi)核中最常用的內(nèi)存管理函數(shù)是 kmallockfree 函數(shù)。這兩個(gè)函數(shù)的原型如下:

    void *kmalloc( size_t size, int flags );
    void kfree( const void *objp );

    注意在 kmalloc 中,惟一兩個(gè)參數(shù)是要分配的對(duì)象的大小和一組標(biāo)志(請(qǐng)參看 表 2 中的部分列表)。但是 kmallockfree 使用了類似于前面定義的函數(shù)的 slab 緩存。kmalloc 沒有為要從中分配對(duì)象的某個(gè) slab 緩存命名,而是循環(huán)遍歷可用緩存來查找可以滿足大小限制的緩存。找到之后,就(使用 __kmem_cache_alloc)分配一個(gè)對(duì)象。要使用 kfree 釋放對(duì)象,從中分配對(duì)象的緩存可以通過調(diào)用 virt_to_cache 確定。這個(gè)函數(shù)會(huì)返回一個(gè)緩存引用,然后在 __cache_free 調(diào)用中使用該引用釋放對(duì)象。

    其他函數(shù)

    slab 緩存 API 還提供了其他一些非常有用的函數(shù)。 kmem_cache_size 函數(shù)會(huì)返回這個(gè)緩存所管理的對(duì)象的大小。您也可以通過調(diào)用 kmem_cache_name 來檢索給定緩存的名稱(在創(chuàng)建緩存時(shí)定義)。緩存可以通過釋放其中的空閑 slab 進(jìn)行收縮。這可以通過調(diào)用 kmem_cache_shrink 實(shí)現(xiàn)。注意這個(gè)操作(稱為回收)是由內(nèi)核定期自動(dòng)執(zhí)行的(通過 kswapd)。

    unsigned int kmem_cache_size( struct kmem_cache *cachep );
    const char *kmem_cache_name( struct kmem_cache *cachep );
    int kmem_cache_shrink( struct kmem_cache *cachep );


    回頁首

    slab 緩存的示例用法

    下面的代碼片斷展示了創(chuàng)建新 slab 緩存、從緩存中分配和釋放對(duì)象然后銷毀緩存的過程。首先,必須要定義一個(gè) kmem_cache 對(duì)象,然后對(duì)其進(jìn)行初始化(請(qǐng)參看清單 1)。這個(gè)特定的緩存包含 32 字節(jié)的對(duì)象,并且是硬件緩存對(duì)齊的(由標(biāo)志參數(shù) SLAB_HWCACHE_ALIGN 定義)。


    清單 1. 創(chuàng)建新 slab 緩存
    				
    static struct kmem_cache *my_cachep;

    static void init_my_cache( void )
    {

    my_cachep = kmem_cache_create(
    "my_cache", /* Name */
    32, /* Object Size */
    0, /* Alignment */
    SLAB_HWCACHE_ALIGN, /* Flags */
    NULL, NULL ); /* Constructor/Deconstructor */

    return;
    }

    使用所分配的 slab 緩存,您現(xiàn)在可以從中分配一個(gè)對(duì)象了。清單 2 給出了一個(gè)從緩存中分配和釋放對(duì)象的例子。它還展示了兩個(gè)其他函數(shù)的用法。


    清單 2. 分配和釋放對(duì)象
    				
    int slab_test( void )
    {
    void *object;

    printk( "Cache name is %s"n", kmem_cache_name( my_cachep ) );
    printk( "Cache object size is %d"n", kmem_cache_size( my_cachep ) );

    object = kmem_cache_alloc( my_cachep, GFP_KERNEL );

    if (object) {

    kmem_cache_free( my_cachep, object );

    }

    return 0;
    }

    最后,清單 3 演示了 slab 緩存的銷毀。調(diào)用者必須確保在執(zhí)行銷毀操作過程中,不要從緩存中分配對(duì)象。


    清單 3. 銷毀 slab 緩存
    				
    static void remove_my_cache( void )
    {

    if (my_cachep) kmem_cache_destroy( my_cachep );

    return;
    }


    回頁首

    slab 的 proc 接口

    proc 文件系統(tǒng)提供了一種簡單的方法來監(jiān)視系統(tǒng)中所有活動(dòng)的 slab 緩存。這個(gè)文件稱為 /proc/slabinfo,它除了提供一些可以從用戶空間訪問的可調(diào)整參數(shù)之外,還提供了有關(guān)所有 slab 緩存的詳細(xì)信息。當(dāng)前版本的 slabinfo 提供了一個(gè)標(biāo)題,這樣輸出結(jié)果就更具可讀性。對(duì)于系統(tǒng)中的每個(gè) slab 緩存來說,這個(gè)文件提供了對(duì)象數(shù)量、活動(dòng)對(duì)象數(shù)量以及對(duì)象大小的信息(除了每個(gè) slab 的對(duì)象和頁面之外)。另外還提供了一組可調(diào)整的參數(shù)和 slab 數(shù)據(jù)。

    要調(diào)優(yōu)特定的 slab 緩存,可以簡單地向 /proc/slabinfo 文件中以字符串的形式回轉(zhuǎn) slab 緩存名稱和 3 個(gè)可調(diào)整的參數(shù)。下面的例子展示了如何增加 limit 和 batchcount 的值,而保留 shared factor 不變(格式為 “cache name limit batchcount shared factor”):

    # echo "my_cache 128 64 8" > /proc/slabinfo

    limit 字段表示每個(gè) CPU 可以緩存的對(duì)象的最大數(shù)量。 batchcount 字段是當(dāng)緩存為空時(shí)轉(zhuǎn)換到每個(gè) CPU 緩存中全局緩存對(duì)象的最大數(shù)量。 shared 參數(shù)說明了對(duì)稱多處理器(Symmetric MultiProcessing,SMP)系統(tǒng)的共享行為。

    注意您必須具有超級(jí)用戶的特權(quán)才能在 proc 文件系統(tǒng)中為 slab 緩存調(diào)優(yōu)參數(shù)。


    回頁首

    SLOB 分配器

    對(duì)于小型的嵌入式系統(tǒng)來說,存在一個(gè) slab 模擬層,名為 SLOB。這個(gè) slab 的替代品在小型嵌入式 Linux 系統(tǒng)中具有優(yōu)勢,但是即使它保存了 512KB 內(nèi)存,依然存在碎片和難于擴(kuò)展的問題。在禁用 CONFIG_SLAB 時(shí),內(nèi)核會(huì)回到這個(gè) SLOB 分配器中。更多信息請(qǐng)參看 參考資料 一節(jié)。


    回頁首

    結(jié)束語

    slab 緩存分配器的源代碼實(shí)際上是 Linux 內(nèi)核中可讀性較好的一部分。除了函數(shù)調(diào)用的間接性之外,源代碼也非常直觀,總的來說,具有很好的注釋。如果您希望了解更多有關(guān) slab 緩存分配器的內(nèi)容,建議您從源代碼開始,因?yàn)樗怯嘘P(guān)這種機(jī)制的最新文檔。 下面的 參考資料 一節(jié)提供了介紹 slab 緩存分配器的參考資料,但是不幸的是就目前的 2.6 實(shí)現(xiàn)來說,這些文檔都已經(jīng)過時(shí)了。


    參考資料

    學(xué)習(xí)

    獲得產(chǎn)品和技術(shù)

    • 獲取免費(fèi)的 SEK for Linux,共包含兩張 DVD,其中有用于 Linux 的最新 IBM 試用版軟件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。

    • 利用可直接從 developerWorks 的 IBM 軟件下載資源中心 下載 IBM 試用版軟件,在 Linux 上構(gòu)建您的下一個(gè)開發(fā)項(xiàng)目。

    討論

    關(guān)于作者

    M. Tim Jones

    M. Tim Jones 是一名嵌入式軟件工程師,他是 GNU/Linux Application Programming、AI Application Programming 以及 BSD Sockets Programming from a Multilanguage Perspective 等書的作者。他的工程背景非常廣泛,從同步宇宙飛船的內(nèi)核開發(fā)到嵌入式架構(gòu)設(shè)計(jì),再到網(wǎng)絡(luò)協(xié)議的開發(fā)。Tim 是位于科羅拉多州 Longmont 的 Emulex Corp. 的一名顧問工程師。

    posted on 2010-10-14 11:47 so true 閱讀(379) 評(píng)論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产青草亚洲香蕉精品久久| 国产亚洲成人在线播放va| 91大神亚洲影视在线| 黄色网站软件app在线观看免费| 亚洲精品成人a在线观看| 成人福利在线观看免费视频| 亚洲av午夜成人片精品电影| 在线91精品亚洲网站精品成人| 国产精品国产免费无码专区不卡| 国产99在线|亚洲| 日韩高清在线高清免费| 亚洲国产精华液2020| 国产午夜鲁丝片AV无码免费| 最新亚洲人成网站在线观看| 国产成人免费全部网站 | 亚洲毛片在线观看| 日本免费人成视频在线观看| 亚洲女人18毛片水真多| 91手机看片国产永久免费| 亚洲免费综合色在线视频| 国产免费怕怕免费视频观看| 精品国产污污免费网站入口在线| 亚洲国产精品VA在线观看麻豆| 1000部免费啪啪十八未年禁止观看| 亚洲人成综合网站7777香蕉| 免费观看午夜在线欧差毛片| 99在线免费视频| 亚洲精品在线电影| 免费乱理伦在线播放| 精品国产污污免费网站| 亚洲av专区无码观看精品天堂| 免费国产不卡午夜福在线| 中文字幕日本人妻久久久免费| 亚洲男女性高爱潮网站| 青青青国产免费一夜七次郎| 久久国产免费直播| 亚洲一区二区三区四区视频| 亚洲国产天堂久久久久久| 91成人免费观看| 四虎影视在线看免费观看| 亚洲国产精品国自产电影|