精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

為什么大家都說 ThreadLocal 存在內存泄漏的風險?

開發 前端
使用ThreadLocal?時,如果當前線程中的變量已經使用完畢并且永久不在使用,推薦手動調用移除remove()?方法,可以采用try ... finally?結構,并在finally中清除變量,防止存在潛在的內存溢出風險。

01、背景介紹

在 Java web 項目中,想必很多的同學對ThreadLocal這個類并不陌生,它最常用的應用場景就是用來做對象的跨層傳遞,避免多次傳遞,打破層次之間的約束。

比如下面這個HttpServletRequest參數傳遞的簡單例子!

public class RequestLocal {

    /**
     * 線程本地變量
     */
    private static ThreadLocal<HttpServletRequest> local = new ThreadLocal<>();

    /**
     * 存儲請求對象
     * @param request
     */
    public static void set(HttpServletRequest request){
        local.set(request);
    }

    /**
     * 獲取請求對象
     * @return
     */
    public static HttpServletRequest get(){
        return local.get();
    }

    /**
     * 移除請求對象
     * @return
     */
    public static void remove(){
        local.remove();
    }
}
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 存儲請求對象變量
        RequestLocal.set(req);
        try {

            // 業務邏輯...
        } finally {
            // 請求完畢之后,移除請求對象變量
            RequestLocal.remove();
        }
    }
}
// 在需要的地方,通過 RequestLocal 類獲取HttpServletRequest對象
HttpServletRequest request = RequestLocal.get();

看完以上示例,相信大家對ThreadLocal的使用已經有了大致的認識。

當然ThreadLocal的作用還不僅限如此,作為 Java 多線程模塊的一部分,ThreadLocal也經常被一些面試官作為知識點用來提問,因此只有理解透徹了,回答才能更加游刃有余。

下面我們從ThreadLocal類的源碼解析到使用方式做一次總結,如果有不正之處,請多多諒解,并歡迎批評指出。

02、源碼剖析

ThreadLocal類,也經常被叫做線程本地變量,也有的叫做本地線程變量,意思其實差不多,通俗的解釋:ThreadLocal作用是為變量在每個線程中創建一個副本,這樣每個線程就可以訪問自己內部的副本變量;同時,該變量對其他線程而言是封閉且隔離的。

字面的意思很容易理解,但是實際上ThreadLocal類的實現原理還有點復雜。

打開ThreadLocal類,它總共有 4 個public方法,內容如下!

方法

描述

public void set(T value)

設置當前線程變量

public T get()

獲取當前線程變量

public void remove()

移除當前線程設置的變量

public static ThreadLocal withInitial(Supplier supplier)

自定義初始化當前線程的默認值

其中使用最多的就是set()、get()和remove()方法,至于withInitial()方法,一般在ThreadLocal對象初始化的時候,給定一個默認值,例如下面這個例子!

// 給所有線程初始化一個變量 1
private static ThreadLocal<Integer> localInt = ThreadLocal.withInitial(() -> 1);

下面我們重點來剖析以上三個方法的源碼,最后總結如何正確的使用。

以下源碼解析均基于jdk1.8。

2.1、set 方法

打開ThreadLocal類,set()方法的源碼如下!

public void set(T value) {
    // 首先獲取當前線程對象
    Thread t = Thread.currentThread();
    // 獲取當前線程中的變量 ThreadLocal.ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    // 如果不為空,就設置值
    if (map != null)
        map.set(this, value);
    else
        // 如果為空,初始化一個ThreadLocalMap變量,其中key為當前的threadlocal變量
        createMap(t, value);
}

我們繼續看看createMap()方法的源碼,內容如下!

void createMap(Thread t, T firstValue) {
    // 初始化一個 ThreadLocalMap 對象,并賦予給 Thread 對象
    // 可以發現,其實 ThreadLocalMap 是 Thread 類的一個屬性變量
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    // INITIAL_CAPACITY 變量的初始值為 16
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}
static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

從上面的源碼上你會發現,通過ThreadLocal類設置的變量,最終保存在每個線程自己的ThreadLocal.ThreadLocalMap對象中,其中key是當前線程的ThreadLocal變量,value就是我們設置的變量。

基于這點,可以得出一個結論:每個線程設置的變量只有自己可見,其它線程無法訪問,因為這個變量是線程自己獨有的屬性。

從上面的源碼也可以看出,真正負責存儲value變量的是Entry靜態類,并且這個類繼承了一個WeakReference類。稍有不同的是,Entry靜態類中的key是一個弱引用類型對象,而value是一個強引用類型對象。這樣設計的好處在于,弱引用的對象更容易被 GC 回收,當ThreadLocal對象不再被其他對象使用時,可以被垃圾回收器自動回收,避免可能的內存泄漏。關于這一點,我們在下文再詳細的介紹。

最后我們再來看看map.set(this, value)這個方法的源碼邏輯,內容如下!

private void set(ThreadLocal<?> key, Object value) {
    Entry[] tab = table;
    int len = tab.length;
    // 根據hash和位運算,計算出數組中的存儲位置
    int i = key.threadLocalHashCode & (len-1);
    // 循環遍歷檢查計算出來的位置上是否被占用
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        // 進入循環體內,說明當前位置已經被占用了
        ThreadLocal<?> k = e.get();
        // 如果key相同,直接進行覆蓋
        if (k == key) {
            e.value = value;
            return;
        }
        // 如果key為空,說明key被回收了,重新覆蓋
        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }
    // 當沒有被占用,循環結束之后,取最后計算的空位,進行存儲
    tab[i] = new Entry(key, value);
    int sz = ++size;
    if (!cleanSomeSlots(i, sz) && sz >= threshold)
        rehash();
}
private static int nextIndex(int i, int len) {
    // 下標依次自增
    return ((i + 1 < len) ? i + 1 : 0);
}

從上面的源碼分析可以看出,ThreadLocalMap和HashMap,雖然都是鍵值對的方式存儲數據,當在數組中存儲數據的下表沖突時,存儲數據的方式有很大的不同。jdk1.8種的HashMap采用的是鏈表法和紅黑樹來解決下表沖突,當

ThreadLocalMap采用的是開放尋址法來解決hash沖突,簡單的說就是當hash出來的存儲位置相同但key不一樣時,會繼續尋找下一個存儲位置,直到找到空位來存儲數據。

圖片圖片

而jdk1.7中的HashMap采用的是鏈表法來解決hash沖突,當hash出來的存儲位置相同但key不一樣時,會將變量通過鏈表的方式掛在數組節點上。

為了實現更高的讀寫效率,jdk1.8中的HashMap就更為復雜了,當沖突的鏈表長度超過 8 時,鏈表會轉變成紅黑樹,在此不做過多的講解,有興趣的同學可以翻看關于HashMap的源碼分析文章。

一路分析下來,是不是感覺set()方法還是挺復雜的,總結下來set()大致的邏輯有以下幾個步驟:

  • 1.首先獲取當前線程對象,檢查當前線程中的ThreadLocalMap是否存在
  • 2.如果不存在,就給線程創建一個ThreadLocal.ThreadLocalMap對象
  • 3.如果存在,就設置值,存儲過程中如果存在 hash 沖突時,采用開放尋址法,重新找一個空位進行存儲

2.2、get 方法

了解完set()方法之后,get()方法就更容易了,get()方法的源碼如下!

public T get() {
    // 獲取當前線程對象
    Thread t = Thread.currentThread();
    // 從當前線程對象中獲取 ThreadLocalMap 對象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 如果有值,就返回
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 如果沒有值,重新初始化默認值
    return setInitialValue();
}

這里我們要重點看下 map.getEntry(this)這個方法,源碼如下!

private Entry getEntry(ThreadLocal<?> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    // 如果找到key,直接返回
    if (e != null && e.get() == key)
        return e;
    else
        // 如果找不到,就嘗試清理,如果你總是訪問存在的key,那么這個清理永遠不會進來
        return getEntryAfterMiss(key, i, e);
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
    Entry[] tab = table;
    int len = tab.length;

    while (e != null) {
        // e指的是entry ,也就是一個弱引用
        ThreadLocal<?> k = e.get();
        // 如果找到了,就返回
        if (k == key)
            return e;
        if (k == null)
            // 如果key為null,說明已經被回收了,同時將value設置為null,以便進行回收
            expungeStaleEntry(i);
        else
            // 如果key不是要找的那個,那說明有hash沖突,繼續找下一個entry
            i = nextIndex(i, len);
        e = tab[i];
    }
    return null;
}

從上面的源碼可以看出,get()方法邏輯,總共有以下幾個步驟:

  • 1.首先獲取當前線程對象,從當前線程對象中獲取 ThreadLocalMap 對象
  • 2.然后判斷ThreadLocalMap是否存在,如果存在,就嘗試去獲取最終的value
  • 3.如果不存在,就重新初始化默認值,以便清理舊的value值

其中expungeStaleEntry()方法是真正用于清理value值的,setInitialValue()方法也具備清理舊的value變量作用。

從上面的代碼可以看出,ThreadLocal為了清楚value變量,花了不少的心思,其實本質都是為了防止ThreadLocal出現可能的內存泄漏。

2.3、remove 方法

我們再來看看remove()方法,源碼如下!

public void remove() {
    // 獲取當前線程里面的 ThreadLocalMap 對象
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        // 如果不為空,就移除
        m.remove(this);
}
private void remove(ThreadLocal<?> key) {
    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);
    // 循環遍歷目標key,然后將key和value都設置為null
    for (Entry e = tab[i];
         e != null;
         e = tab[i = nextIndex(i, len)]) {
        if (e.get() == key) {
            e.clear();
            // 清理value值
            expungeStaleEntry(i);
            return;
        }
    }
}

remove()方法邏輯比較簡單,首先獲取當前線程的ThreadLocalMap對象,然后循環遍歷key,將目標key以及對應的value都設置為null。

從以上的源碼剖析中,可以得出一個結論:不管是set()、get()還是remove(),其實都會主動清理無效的value數據,因此實際開發過程中,沒有必要過于擔心內存泄漏的問題。

03、為什么要用 WeakReference?

另外細心的同學可能會發現,ThreadLocal中真正負責存儲key和value變量的是Entry靜態類,并且它繼承了一個WeakReference類。

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

關于WeakReference類,我們在上文只是簡單的說了一下,可能有的同學不太清楚,這個再次簡要的介紹一下。

了解過WeakHashMap類的同學,可能對WeakReference有印象,它表示當前對象為弱引用類型。

在 Java 中,對象有四種引用類型,分別是:強引用、軟引用、弱引用和虛引用,級別從高依次到低。

不同引用類型的對象,GC 回收的方式也不一樣,對于強引用類型,不會被垃圾收集器回收,即使當內存不足時,另可拋異常也不會主動回收,防止程序出現異常,通常我們自定義的類,初始化的對象都是強引用類型;對于軟引用類型的對象,當不存在外部強引用的時候,GC 會在內存不足的時候,進行回收;對于弱引用類型的對象,當不存在外部強引用的時候,GC 掃描到時會進行回收;對于虛引用,GC 會在任何時候都可能進行回收。

下面我們看一個簡單的示例,更容易直觀的了解它。

public static void main(String[] args) {
        Map weakHashMap = new WeakHashMap();
        //向weakHashMap中添加4個元素
        for (int i = 0; i < 3; i++) {
            weakHashMap.put("key-"+i, "value-"+ i);
        }
        //輸出添加的元素
        System.out.println("數組長度:"+weakHashMap.size() + ",輸出結果:" + weakHashMap);
        //主動觸發一次GC
        System.gc();
        //再輸出添加的元素
        System.out.println("數組長度:"+weakHashMap.size() + ",輸出結果:" + weakHashMap);
    }

輸出結果:

數組長度:3,輸出結果:{key-2=value-2, key-1=value-1, key-0=value-0}
數組長度:3,輸出結果:{}

以上存儲的弱引用對象,與外部對象沒有強關聯,當主動調用 GC 回收器的時候,再次查詢WeakHashMap里面的數據的時候,弱引用對象收回,所以內容為空。其中WeakHashMap類底層使用的數據存儲對象,也是繼承了WeakReference。

采用WeakReference這種弱引用的方式,當不存在外部強引用的時候,就會被垃圾收集器自動回收掉,減小內存空間壓力。

需要注意的是,Entry靜態類中僅僅只是key被設計成弱引用類型,value依然是強引用類型。

回歸正題,為什么ThreadLocalMap類中的Entry靜態類中的key需要被設計成弱引用類型?

我們先看一張Entry對象的依賴圖!

圖片圖片

如上圖所示,Entry持有ThreadLocal對象的引用,如果沒有設置引用類型,這個引用鏈就全是強引用,當線程沒有結束時,它持有的強引用,包括遞歸下去的所有強引用都不會被垃圾回收器回收;只有當線程生命周期結束時,才會被回收。

哪怕顯式的設置threadLocal = null,它也無法被垃圾收集器回收,因為Entry和key存在強關聯!

如果Entry中的key設置成弱引用,當threadLocal = null時,key就可以被垃圾收集器回收,進一步減少內存使用空間。

但是也僅僅只是回收key,不能回收value,如果這個線程運行時間非常長,又沒有調用set()、get()或者remove()方法,隨著線程數的增多可能會有內存溢出的風險。

因此在實際的使用中,想要徹底回收value,使用完之后可以顯式調用一下remove()方法。

04、應用介紹

通過以上的源碼分析,相信大家對ThreadLocal類已經有了一些認識,它主要的作用是在線程內實現變量的傳遞,每個線程只能看到自己設定的變量。

我們可以看一個簡單的示例!

public static void main(String[] args) {
    ThreadLocal threadLocal = new ThreadLocal();
    threadLocal.set("main");

    for (int i = 0; i < 5; i++) {
        final int j = i;
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 設置變量
                threadLocal.set(String.valueOf(j));
                // 獲取設置的變量
                System.out.println("thread name:" + Thread.currentThread().getName() + ", 內容:" + threadLocal.get());
            }
        }).start();
    }
    
    System.out.println("thread name:" + Thread.currentThread().getName() + ", 內容:" + threadLocal.get());
}

輸出結果:

thread name:Thread-0, 內容:0
thread name:Thread-1, 內容:1
thread name:Thread-2, 內容:2
thread name:Thread-3, 內容:3
thread name:main, 內容:main
thread name:Thread-4, 內容:4

從運行結果上可以很清晰的看出,每個線程只能看到自己設置的變量,其它線程不可見。

ThreadLocal可以實現線程之間的數據隔離,在實際的業務開發中,使用非常廣泛,例如文章開頭介紹的HttpServletRequest參數的上下文傳遞。

05、小結

最后我們來總結一下,ThreadLocal類經常被叫做線程本地變量,它確保每個線程的ThreadLocal變量都是各自獨立的,其它線程無法訪問,實現線程之間數據隔離的效果。

ThreadLocal適合在一個線程的處理流程中實現參數上下文的傳遞,避免同一個參數在所有的方法中傳遞。

使用ThreadLocal時,如果當前線程中的變量已經使用完畢并且永久不在使用,推薦手動調用移除remove()方法,可以采用try ... finally結構,并在finally中清除變量,防止存在潛在的內存溢出風險。

06、參考

1、https://www.cnblogs.com/xrq730/p/4854813.html

2、https://www.cnblogs.com/xrq730/p/4854820.html

3、https://zhuanlan.zhihu.com/p/102744180

責任編輯:武曉燕 來源: 潘志的研發筆記
相關推薦

2021-08-10 09:58:59

ThreadLocal內存泄漏

2025-04-01 05:22:00

JavaThread變量

2020-07-06 08:15:59

SQLSELECT優化

2018-10-25 15:24:10

ThreadLocal內存泄漏Java

2022-05-09 14:09:23

多線程線程安全

2019-05-23 10:59:24

Java內存 C++

2024-03-22 13:31:00

線程策略線程池

2020-09-10 07:40:28

ThreadLocal內存

2022-10-18 08:38:16

內存泄漏線程

2021-02-18 16:53:44

內存ThreadLocal線程

2011-05-24 16:39:09

Cfree()

2020-11-04 13:01:38

FastThreadLocalJDK

2022-07-26 07:14:20

線程隔離Thread

2024-03-22 12:29:03

HashMap線程

2023-05-29 07:17:48

內存溢出場景

2021-08-10 16:50:37

內核內存管理

2021-03-10 09:40:50

Linux命令文件

2019-11-06 19:21:07

Pythonargparse解釋器

2017-12-15 14:10:20

深度學習本質邊緣識別

2020-09-11 07:38:50

內存泄漏檢測
點贊
收藏

51CTO技術棧公眾號

亚洲曰韩产成在线| 狠狠色狠狠色合久久伊人| 亚洲白拍色综合图区| 欧美三级在线观看视频| 全部免费毛片在线播放网站| 日韩国产欧美在线观看| 久久夜色精品亚洲噜噜国产mv| 国产又粗又猛又爽又黄| 成人教育av| 亚洲日本电影在线| 欧美高清性xxxxhd| 亚洲综合国产精品| 高潮毛片无遮挡| 国产999精品在线观看| 婷婷开心激情综合| 天天做天天爱天天高潮| 欧美女同网站| 国产激情视频一区二区三区欧美 | 欧美一级精品大片| 久久久久人妻精品一区三寸| 黄色网页网址在线免费| 91一区二区三区在线观看| 成人国产亚洲精品a区天堂华泰| 国产福利拍拍拍| 久久久久久久久久久9不雅视频| 日韩激情视频在线| 北条麻妃亚洲一区| jizz欧美| 色综合视频在线观看| 青青草综合在线| 香蕉视频网站在线观看| 久久久一区二区三区| 国产精品区一区二区三在线播放| 一级黄色片在线观看| 欧美日韩国产综合网| 亚洲精品suv精品一区二区| www.久久com| 日韩免费在线电影| 欧洲另类一二三四区| 免费看又黄又无码的网站| 色吊丝在线永久观看最新版本| 国产成人免费视频一区| 91久久久久久久久久久久久| 国产情侣免费视频| 久久福利毛片| 欧美亚洲国产日本| 久久综合久久鬼| 欧美欧美天天天天操| 最新91在线视频| 高清国产在线观看| 精品av一区二区| 亚洲网站视频福利| 日本一二三不卡视频| 少妇一区二区视频| 亚洲三级av在线| 国产小视频自拍| 黄色av中文字幕| 99精品在线免费在线观看| 在线看日韩av| 国产成人在线网址| 天天av综合| 欧美成人第一页| 国产成人久久久久| 在线观看日韩| 久久青草福利网站| 精品在线播放视频| 裸体一区二区| 国产精品爽黄69| 91麻豆国产在线| 国产精品一品视频| 国产精品久久久久久久久久直播 | 日韩中文影院| 欧美亚洲国产一卡| 日韩一区二区三区不卡视频| 亚洲视频资源| 欧美大片一区二区| 北岛玲一区二区| 国际精品欧美精品| 久久精品亚洲一区| 黄色一级视频在线观看| 国产精品国产三级国产普通话对白| 亚洲天堂一区二区三区四区| 欧美人成在线视频| 日本系列第一页| 老牛影视一区二区三区| 91精品在线看| 欧美一区二区公司| 久久精品人人做人人综合 | 亚洲中文字幕无码av| 欧美日韩导航| 在线观看久久久久久| 69av.com| 爽好多水快深点欧美视频| 91社区国产高清| 日韩一区免费视频| 国产欧美日本一区二区三区| 性生活免费观看视频| 国产亚洲成av人片在线观看| 一本大道久久a久久精二百| 99re精彩视频| 狼人精品一区二区三区在线| 伊人久久男人天堂| 精品无码久久久久| 日韩电影在线观看电影| av日韩免费电影| 国产区高清在线| 一区二区三区日韩欧美| 欧美日韩一区二区在线免费观看| **日韩最新| 日韩精品极品视频免费观看| 黑鬼狂亚洲人videos| 久久福利毛片| 国产精品久久久久免费| 在线观看a视频| 精品国产福利在线| 五月天婷婷在线观看视频| 希岛爱理av免费一区二区| 日韩日本欧美亚洲| 无码人妻丰满熟妇区bbbbxxxx| 国产精品夜夜爽| 午夜欧美性电影| 黄色软件视频在线观看| 日韩亚洲欧美成人一区| 免费黄色国产视频| 久久九九国产| 自拍偷拍欧美激情| 中文字幕欧美日韩一区二区| 美女100%一区| 亚洲成av人乱码色午夜| 日本一二三区在线观看| 日本中文字幕一区| 欧美激情视频一区二区三区| 日本一本在线免费福利| 欧美精品 国产精品| 三年中国中文观看免费播放| 久久激情久久| 九9re精品视频在线观看re6| 久久免费电影| 日韩欧美一区二区不卡| 精品国产视频在线观看| 免费成人av资源网| 亚洲国产精品毛片| 欧美一区久久久| 亚洲精品中文字| 天天操夜夜操视频| 91丨九色丨国产丨porny| 免费无码毛片一区二三区| 日韩中文一区二区| 欧美成人精品一区二区| 国产又黄又粗又硬| 亚洲女人的天堂| 亚洲国产欧美日韩在线| 欧美在线亚洲| 成人在线观看av| xxx.xxx欧美| 亚洲国产成人精品女人久久久| 国产第100页| 成人性色生活片| 日韩欧美一区二| 在线日韩网站| 国产欧美日韩精品在线观看| 瑟瑟视频在线| 欧美一级二级三级蜜桃| 欧美精品乱码视频一二专区| 成人精品gif动图一区| 香港三级韩国三级日本三级| 伊人久久大香线蕉无限次| 国产精品高潮粉嫩av| 暖暖日本在线观看| 日韩亚洲欧美中文三级| 欧美一级视频免费观看| 久久精品一区二区三区不卡| xx欧美撒尿嘘撒尿xx| 外国成人免费视频| 国产精品永久入口久久久| 日本黄色免费在线| 亚洲一区www| 国产精品一二三四五区| 亚洲欧美电影一区二区| 三级男人添奶爽爽爽视频| 日本不卡高清视频| www.-级毛片线天内射视视| 波多野结衣一区二区三区免费视频| 韩日欧美一区二区| 国产午夜精品一区理论片| 欧美人与性动xxxx| 国产午夜福利一区二区| 国产夜色精品一区二区av| 日韩成人av免费| 国产婷婷精品| 手机成人av在线| 国产精品对白久久久久粗| 国产精品第一区| 在线观看h网| 亚洲一品av免费观看| www.成人在线观看| 日本久久一区二区三区| 国产免费无码一区二区视频| 91美女视频网站| 亚洲色图偷拍视频| 亚洲伊人网站| 黄黄视频在线观看| 精品免费一区二区| 91色在线视频| 99re66热这里只有精品4| 久久久久久有精品国产| 日本中文字幕视频在线| 亚洲国产又黄又爽女人高潮的| 91麻豆国产在线| 色伊人久久综合中文字幕| 欧美精品99久久久| 国产精品国产三级国产普通话三级 | 久久国产精品区| 国产不卡一区二区视频| 99精品视频在线| 欧美日韩精品久久| 视频精品国内| 91精品久久久久久| 日韩电影大全网站| 午夜免费日韩视频| 超碰在线观看免费| 中文字幕亚洲综合久久筱田步美| 亚洲成a人片在线| 欧美调教femdomvk| 青青视频在线免费观看| 欧美日韩日本国产| www.99re7.com| 玉米视频成人免费看| 五月天免费网站| 国产女人水真多18毛片18精品视频| aaaaaav| 99久久综合精品| 涩视频在线观看| 国产精品夜夜嗨| 深爱五月综合网| 狠狠色伊人亚洲综合成人| 国产精品视频分类| 日韩制服丝袜av| 日韩毛片在线免费看| 国产亚洲高清视频| 国产欧美日韩网站| 亚洲国产激情| 黄色大片中文字幕| 亚洲激情专区| 成人免费观看cn| 99re国产精品| 日本中文字幕网址| 亚洲自啪免费| 久久国产成人精品国产成人亚洲| 日韩视频在线一区二区三区| av网站大全免费| 最新日韩在线| 欧美亚洲一二三区| 丝瓜av网站精品一区二区 | 成人交换视频| 国产精品高潮在线| 成人做爰视频www| 国产欧亚日韩视频| 国色天香久久精品国产一区| 亚洲一区二区三区sesese| 伊人www22综合色| 国产在线欧美日韩| 亚洲深夜福利在线观看| 亚洲国产另类久久久精品极度| 99久久99久久精品国产片桃花| 中文字幕日韩一区二区三区不卡| 在线免费观看日本欧美爱情大片| 久久www视频| 99这里有精品| 亚洲黄色小视频在线观看| 精品亚洲欧美一区| 久草福利在线观看| 2020日本不卡一区二区视频| 国产又粗又硬视频| 伊人夜夜躁av伊人久久| 日韩 欧美 中文| 欧美三级资源在线| 99久久国产热无码精品免费| 亚洲福利在线观看| 黄色小视频在线免费观看| 日日骚久久av| 丰满诱人av在线播放| 国产成人精品av在线| 精品国产乱码久久久久久樱花| 精品国产一区二区三区日日嗨| 久9久9色综合| 韩国无码av片在线观看网站| 久久福利影视| 一区二区在线免费观看视频| 久久一二三国产| 成人在线观看免费完整| 福利视频导航一区| 91丨九色丨蝌蚪丨对白| 亚洲成人久久久久| 久久精品一区二区免费播放| 国产精品久久观看| 玖玖精品在线视频| 国产精品久久久久久久久久妞妞| 特级丰满少妇一级| 成人久久18免费网站麻豆| 国产伦精品一区二区三区视频女| 亚洲图片自拍偷拍| 自拍偷拍色综合| 亚洲国产精品资源| 日本韩国在线视频爽| 136fldh精品导航福利| 精品成人18| 日韩在线三区| 国产亚洲福利| 中文字幕在线国产| 亚洲欧美自拍偷拍色图| 久草视频一区二区| 精品蜜桃在线看| 欧美性videos| 国产精品白丝jk喷水视频一区| 红杏视频成人| 91视频 - 88av| 激情亚洲综合在线| 真实乱视频国产免费观看 | 日韩欧美国产另类| 亚洲第一中文字幕在线观看| 免费日本一区二区三区视频| 国产成人免费av| 日韩深夜福利| 日韩伦理在线免费观看| 国产精品99久| 希岛爱理中文字幕| 欧美久久一区二区| 97在线观看免费观看高清 | 欧美精品18videosex性欧美| 国产人妖一区| 亚欧精品在线| 日本美女视频一区二区| 白白色免费视频| 欧美性高潮床叫视频| 午夜激情小视频| 久久人人看视频| silk一区二区三区精品视频| 国产午夜精品视频一区二区三区| 狠狠色丁香久久婷婷综合丁香| 男女男精品视频网站| 欧美三级视频在线观看| 成人高清网站| 国产精品影片在线观看| 91日韩在线| 午夜国产福利在线观看| 国产精品久久久久久久久晋中| 依依成人在线视频| 色久欧美在线视频观看| 青草综合视频| 国产日产欧美一区二区| 国产一区二区三区视频在线播放| 性欧美疯狂猛交69hd| 日韩一二三区不卡| heyzo在线播放| 精品视频在线观看| 免费看的黄色欧美网站| 亚洲资源在线看| 涩涩涩视频在线观看| 99国产在线观看| 激情一区二区| 懂色av粉嫩av蜜乳av| 色欧美日韩亚洲| 五月婷婷在线视频| 91久久精品一区二区别| 国模吧视频一区| 中文字幕5566| 欧美影院午夜播放| 国产在线观看a视频| 成人女人免费毛片| 久久国产精品99国产| 中文字幕美女视频| 欧美一区二区三区男人的天堂| 久久一卡二卡| 欧美一级二级三级九九九| 麻豆国产91在线播放| 午夜精品一区二区三区视频| 精品黑人一区二区三区久久| 中文在线аv在线| 伊人久久av导航| 不卡电影免费在线播放一区| 久久久久精彩视频| 超在线视频97| 自拍欧美一区| 中文 日韩 欧美| 欧美日韩一区二区在线| 在线播放毛片| 精选一区二区三区四区五区| 九九国产精品视频| 国产高潮久久久| 久久精品亚洲国产| 亚洲香蕉视频| 最好看的中文字幕| 在线国产亚洲欧美| 国产在线xxx| 亚洲欧美日韩另类精品一区二区三区| 粉嫩久久99精品久久久久久夜 | 国产欧美一区二区色老头| 992在线观看| 日韩精品亚洲元码|