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

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

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


       To build a better world !

    Java內(nèi)存泄露的理解與解決

    Java內(nèi)存泄露的理解與解決 

    轉(zhuǎn)載請(qǐng)注明出處:http://m.tkk7.com/zh-weir/archive/2011/02/23/345007.html


    Java內(nèi)存管理機(jī)制

    C++語(yǔ)言中,如果需要?jiǎng)討B(tài)分配一塊內(nèi)存,程序員需要負(fù)責(zé)這塊內(nèi)存的整個(gè)生命周期。從申請(qǐng)分配、到使用、再到最后的釋放。這樣的過(guò)程非常靈活,但是卻十分繁瑣,程序員很容易由于疏忽而忘記釋放內(nèi)存,從而導(dǎo)致內(nèi)存的泄露。Java語(yǔ)言對(duì)內(nèi)存管理做了自己的優(yōu)化,這就是垃圾回收機(jī)制。Java的幾乎所有內(nèi)存對(duì)象都是在堆內(nèi)存上分配(基本數(shù)據(jù)類(lèi)型除外),然后由GCgarbage collection)負(fù)責(zé)自動(dòng)回收不再使用的內(nèi)存。

        上面是Java內(nèi)存管理機(jī)制的基本情況。但是如果僅僅理解到這里,我們?cè)趯?shí)際的項(xiàng)目開(kāi)發(fā)中仍然會(huì)遇到內(nèi)存泄漏的問(wèn)題。也許有人表示懷疑,既然Java的垃圾回收機(jī)制能夠自動(dòng)的回收內(nèi)存,怎么還會(huì)出現(xiàn)內(nèi)存泄漏的情況呢?這個(gè)問(wèn)題,我們需要知道GC在什么時(shí)候回收內(nèi)存對(duì)象,什么樣的內(nèi)存對(duì)象會(huì)被GC認(rèn)為是“不再使用”的。

        Java中對(duì)內(nèi)存對(duì)象的訪(fǎng)問(wèn),使用的是引用的方式。在Java代碼中我們維護(hù)一個(gè)內(nèi)存對(duì)象的引用變量,通過(guò)這個(gè)引用變量的值,我們可以訪(fǎng)問(wèn)到對(duì)應(yīng)的內(nèi)存地址中的內(nèi)存對(duì)象空間。在Java程序中,這個(gè)引用變量本身既可以存放堆內(nèi)存中,又可以放在代碼棧的內(nèi)存中(與基本數(shù)據(jù)類(lèi)型相同)。GC線(xiàn)程會(huì)從代碼棧中的引用變量開(kāi)始跟蹤,從而判定哪些內(nèi)存是正在使用的。如果GC線(xiàn)程通過(guò)這種方式,無(wú)法跟蹤到某一塊堆內(nèi)存,那么GC就認(rèn)為這塊內(nèi)存將不再使用了(因?yàn)榇a中已經(jīng)無(wú)法訪(fǎng)問(wèn)這塊內(nèi)存了)。

     

        通過(guò)這種有向圖的內(nèi)存管理方式,當(dāng)一個(gè)內(nèi)存對(duì)象失去了所有的引用之后,GC就可以將其回收。反過(guò)來(lái)說(shuō),如果這個(gè)對(duì)象還存在引用,那么它將不會(huì)被GC回收,哪怕是Java虛擬機(jī)拋出OutOfMemoryError

    Java內(nèi)存泄露

        一般來(lái)說(shuō)內(nèi)存泄漏有兩種情況。一種情況如在C/C++語(yǔ)言中的,在堆中的分配的內(nèi)存,在沒(méi)有將其釋放掉的時(shí)候,就將所有能訪(fǎng)問(wèn)這塊內(nèi)存的方式都刪掉(如指針重新賦值);另一種情況則是在內(nèi)存對(duì)象明明已經(jīng)不需要的時(shí)候,還仍然保留著這塊內(nèi)存和它的訪(fǎng)問(wèn)方式(引用)。第一種情況,在Java中已經(jīng)由于垃圾回收機(jī)制的引入,得到了很好的解決。所以,Java中的內(nèi)存泄漏,主要指的是第二種情況。

        可能光說(shuō)概念太抽象了,大家可以看一下這樣的例子:

    1 Vector v=new Vector(10);
    2 for (int i=1;i<100; i++){
    3 Object o=new Object();
    4 v.add(o);
    5 o=null;
    6 }

       
        在這個(gè)例子中,代碼棧中存在Vector對(duì)象的引用vObject對(duì)象的引用o。在For循環(huán)中,我們不斷的生成新的對(duì)象,然后將其添加到Vector對(duì)象中,之后將o引用置空。問(wèn)題是當(dāng)o引用被置空后,如果發(fā)生GC,我們創(chuàng)建的Object對(duì)象是否能夠被GC回收呢?答案是否定的。因?yàn)椋?/font>GC在跟蹤代碼棧中的引用時(shí),會(huì)發(fā)現(xiàn)v引用,而繼續(xù)往下跟蹤,就會(huì)發(fā)現(xiàn)v引用指向的內(nèi)存空間中又存在指向Object對(duì)象的引用。也就是說(shuō)盡管o引用已經(jīng)被置空,但是Object對(duì)象仍然存在其他的引用,是可以被訪(fǎng)問(wèn)到的,所以GC無(wú)法將其釋放掉。如果在此循環(huán)之后,Object對(duì)象對(duì)程序已經(jīng)沒(méi)有任何作用,那么我們就認(rèn)為此Java程序發(fā)生了內(nèi)存泄漏。

        盡管對(duì)于C/C++中的內(nèi)存泄露情況來(lái)說(shuō),Java內(nèi)存泄露導(dǎo)致的破壞性小,除了少數(shù)情況會(huì)出現(xiàn)程序崩潰的情況外,大多數(shù)情況下程序仍然能正常運(yùn)行。但是,在移動(dòng)設(shè)備對(duì)于內(nèi)存和CPU都有較嚴(yán)格的限制的情況下,Java的內(nèi)存溢出會(huì)導(dǎo)致程序效率低下、占用大量不需要的內(nèi)存等問(wèn)題。這將導(dǎo)致整個(gè)機(jī)器性能變差,嚴(yán)重的也會(huì)引起拋出OutOfMemoryError,導(dǎo)致程序崩潰。

    一般情況下內(nèi)存泄漏的避免

        在不涉及復(fù)雜數(shù)據(jù)結(jié)構(gòu)的一般情況下,Java的內(nèi)存泄露表現(xiàn)為一個(gè)內(nèi)存對(duì)象的生命周期超出了程序需要它的時(shí)間長(zhǎng)度。我們有時(shí)也將其稱(chēng)為“對(duì)象游離”。

    例如:

     1 public class FileSearch{
     2 
     3     private byte[] content;
     4     private File mFile;
     5     
     6     public FileSearch(File file){
     7         mFile = file;
     8     }
     9 
    10     public boolean hasString(String str){
    11         int size = getFileSize(mFile);
    12         content = new byte[size];
    13         loadFile(mFile, content);
    14         
    15         String s = new String(content);
    16         return s.contains(str);
    17     }
    18 }


        在這段代碼中,FileSearch類(lèi)中有一個(gè)函數(shù)
    hasString,用來(lái)判斷文檔中是否含有指定的字符串。流程是先將mFile加載到內(nèi)存中,然后進(jìn)行判斷。但是,這里的問(wèn)題是,將content聲明為了實(shí)例變量,而不是本地變量。于是,在此函數(shù)返回之后,內(nèi)存中仍然存在整個(gè)文件的數(shù)據(jù)。而很明顯,這些數(shù)據(jù)我們后續(xù)是不再需要的,這就造成了內(nèi)存的無(wú)故浪費(fèi)。

        要避免這種情況下的內(nèi)存泄露,要求我們以C/C++的內(nèi)存管理思維來(lái)管理自己分配的內(nèi)存。第一,是在聲明對(duì)象引用之前,明確內(nèi)存對(duì)象的有效作用域。在一個(gè)函數(shù)內(nèi)有效的內(nèi)存對(duì)象,應(yīng)該聲明為local變量,與類(lèi)實(shí)例生命周期相同的要聲明為實(shí)例變量……以此類(lèi)推。第二,在內(nèi)存對(duì)象不再需要時(shí),記得手動(dòng)將其引用置空。

    復(fù)雜數(shù)據(jù)結(jié)構(gòu)中的內(nèi)存泄露問(wèn)題

        在實(shí)際的項(xiàng)目中,我們經(jīng)常用到一些較為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)用于緩存程序運(yùn)行過(guò)程中需要的數(shù)據(jù)信息。有時(shí),由于數(shù)據(jù)結(jié)構(gòu)過(guò)于復(fù)雜,或者我們存在一些特殊的需求(例如,在內(nèi)存允許的情況下,盡可能多的緩存信息來(lái)提高程序的運(yùn)行速度等情況),我們很難對(duì)數(shù)據(jù)結(jié)構(gòu)中數(shù)據(jù)的生命周期作出明確的界定。這個(gè)時(shí)候,我們可以使用Java中一種特殊的機(jī)制來(lái)達(dá)到防止內(nèi)存泄露的目的。

        之前我們介紹過(guò),JavaGC機(jī)制是建立在跟蹤內(nèi)存的引用機(jī)制上的。而在此之前,我們所使用的引用都只是定義一個(gè)“Object o;”這樣形式的。事實(shí)上,這只是Java引用機(jī)制中的一種默認(rèn)情況,除此之外,還有其他的一些引用方式。通過(guò)使用這些特殊的引用機(jī)制,配合GC機(jī)制,就可以達(dá)到一些我們需要的效果。

    Java中的幾種引用方式

        Java中有幾種不同的引用方式,它們分別是:強(qiáng)引用、軟引用、弱引用和虛引用。下面,我們首先詳細(xì)地了解下這幾種引用方式的意義。

        
          強(qiáng)引用

    在此之前我們介紹的內(nèi)容中所使用的引用都是強(qiáng)引用,這是使用最普遍的引用。如果一個(gè)對(duì)象具有強(qiáng)引用,那就類(lèi)似于必不可少的生活用品,垃圾回收器絕不會(huì)回收它。當(dāng)內(nèi)存空 間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足問(wèn)題。

    軟引用(SoftReference

    SoftReference 類(lèi)的一個(gè)典型用途就是用于內(nèi)存敏感的高速緩存。SoftReference 的原理是:在保持對(duì)對(duì)象的引用時(shí)保證在 JVM 報(bào)告內(nèi)存不足情況之前將清除所有的軟引用。關(guān)鍵之處在于,垃圾收集器在運(yùn)行時(shí)可能會(huì)(也可能不會(huì))釋放軟可及對(duì)象。對(duì)象是否被釋放取決于垃圾收集器的算法 以及垃圾收集器運(yùn)行時(shí)可用的內(nèi)存數(shù)量。

    弱引用(WeakReference

    WeakReference 類(lèi)的一個(gè)典型用途就是規(guī)范化映射(canonicalized mapping)。另外,對(duì)于那些生存期相對(duì)較長(zhǎng)而且重新創(chuàng)建的開(kāi)銷(xiāo)也不高的對(duì)象來(lái)說(shuō),弱引用也比較有用。關(guān)鍵之處在于,垃圾收集器運(yùn)行時(shí)如果碰到了弱可及對(duì)象,將釋放 WeakReference 引用的對(duì)象。然而,請(qǐng)注意,垃圾收集器可能要運(yùn)行多次才能找到并釋放弱可及對(duì)象。

    虛引用(PhantomReference

    PhantomReference 類(lèi)只能用于跟蹤對(duì)被引用對(duì)象即將進(jìn)行的收集。同樣,它還能用于執(zhí)行 pre-mortem 清除操作。PhantomReference 必須與 ReferenceQueue 類(lèi)一起使用。需要 ReferenceQueue 是因?yàn)樗軌虺洚?dāng)通知機(jī)制。當(dāng)垃圾收集器確定了某個(gè)對(duì)象是虛可及對(duì)象時(shí),PhantomReference 對(duì)象就被放在它的 ReferenceQueue 上。將 PhantomReference 對(duì)象放在 ReferenceQueue 上也就是一個(gè)通知,表明 PhantomReference 對(duì)象引用的對(duì)象已經(jīng)結(jié)束,可供收集了。這使您能夠剛好在對(duì)象占用的內(nèi)存被回收之前采取行動(dòng)。ReferenceReferenceQueue的配合使用。

    GCReferenceReferenceQueue的交互

    A、 GC無(wú)法刪除存在強(qiáng)引用的對(duì)象的內(nèi)存。

    B、 GC發(fā)現(xiàn)一個(gè)只有軟引用的對(duì)象內(nèi)存,那么:

    ① SoftReference對(duì)象的referent 域被設(shè)置為null,從而使該對(duì)象不再引用heap對(duì)象。

    ② SoftReference引用過(guò)的heap對(duì)象被聲明為finalizable

    ③ 當(dāng) heap 對(duì)象的 finalize() 方法被運(yùn)行而且該對(duì)象占用的內(nèi)存被釋放,SoftReference 對(duì)象就被添加到它的 ReferenceQueue(如果后者存在的話(huà))。

    C、 GC發(fā)現(xiàn)一個(gè)只有弱引用的對(duì)象內(nèi)存,那么:

    ① WeakReference對(duì)象的referent域被設(shè)置為null,從而使該對(duì)象不再引用heap對(duì)象。

    ② WeakReference引用過(guò)的heap對(duì)象被聲明為finalizable

    ③ 當(dāng)heap對(duì)象的finalize()方法被運(yùn)行而且該對(duì)象占用的內(nèi)存被釋放時(shí),WeakReference對(duì)象就被添加到它的ReferenceQueue(如果后者存在的話(huà))。

    D、 GC發(fā)現(xiàn)一個(gè)只有虛引用的對(duì)象內(nèi)存,那么:

    ① PhantomReference引用過(guò)的heap對(duì)象被聲明為finalizable

    ② PhantomReference在堆對(duì)象被釋放之前就被添加到它的ReferenceQueue

    值得注意的地方有以下幾點(diǎn):

    1GC在一般情況下不會(huì)發(fā)現(xiàn)軟引用的內(nèi)存對(duì)象,只有在內(nèi)存明顯不足的時(shí)候才會(huì)發(fā)現(xiàn)并釋放軟引用對(duì)象的內(nèi)存。

    2GC對(duì)弱引用的發(fā)現(xiàn)和釋放也不是立即的,有時(shí)需要重復(fù)幾次GC,才會(huì)發(fā)現(xiàn)并釋放弱引用的內(nèi)存對(duì)象。
    3、軟引用和弱引用在添加到ReferenceQueue的時(shí)候,其指向真實(shí)內(nèi)存的引用已經(jīng)被置為空了,相關(guān)的內(nèi)存也已經(jīng)被釋放掉了。而虛引用在添加到ReferenceQueue的時(shí)候,內(nèi)存還沒(méi)有釋放,仍然可以對(duì)其進(jìn)行訪(fǎng)問(wèn)。

        代碼示例

    通過(guò)以上的介紹,相信您對(duì)Java的引用機(jī)制以及幾種引用方式的異同已經(jīng)有了一定了解。光是概念,可能過(guò)于抽象,下面我們通過(guò)一個(gè)例子來(lái)演示如何在代碼中使用Reference機(jī)制。

    1     String str = new String("hello"); //
    2     ReferenceQueue<String> rq = new ReferenceQueue<String>(); //
    3     WeakReference<String> wf = new WeakReference<String>(str, rq); //
    4     str=null//④取消"hello"對(duì)象的強(qiáng)引用
    5     String str1=wf.get(); //⑤假如"hello"對(duì)象沒(méi)有被回收,str1引用"hello"對(duì)象
    6     //假如"hello"對(duì)象沒(méi)有被回收,rq.poll()返回null
    7     Reference<? extends String> ref=rq.poll(); //


    在以上代碼中,注意⑤⑥兩處地方。假如“hello”對(duì)象沒(méi)有被回收wf.get()將返回“hello”字符串對(duì)象,rq.poll()返回null;而加入“hello”對(duì)象已經(jīng)被回收了,那么wf.get()返回nullrq.poll()返回Reference對(duì)象,但是此Reference對(duì)象中已經(jīng)沒(méi)有str對(duì)象的引用了(PhantomReference則與WeakReferenceSoftReference不同)

        引用機(jī)制與復(fù)雜數(shù)據(jù)結(jié)構(gòu)的聯(lián)合應(yīng)用

        了解了GC機(jī)制、引用機(jī)制,并配合上ReferenceQueue,我們就可以實(shí)現(xiàn)一些防止內(nèi)存溢出的復(fù)雜數(shù)據(jù)類(lèi)型。

    例如,SoftReference具有構(gòu)建Cache系統(tǒng)的特質(zhì),因此我們可以結(jié)合哈希表實(shí)現(xiàn)一個(gè)簡(jiǎn)單的緩存系統(tǒng)。這樣既能保證能夠盡可能多的緩存信息,又可以保證Java虛擬機(jī)不會(huì)因?yàn)閮?nèi)存泄露而拋出OutOfMemoryError。這種緩存機(jī)制特別適合于內(nèi)存對(duì)象生命周期長(zhǎng),且生成內(nèi)存對(duì)象的耗時(shí)比較長(zhǎng)的情況,例如緩存列表封面圖片等。對(duì)于一些生命周期較長(zhǎng),但是生成內(nèi)存對(duì)象開(kāi)銷(xiāo)不大的情況,使用WeakReference能夠達(dá)到更好的內(nèi)存管理的效果。

    SoftHashmap的源碼一份,相信看過(guò)之后,大家會(huì)對(duì)Reference機(jī)制的應(yīng)用有更深入的理解。

      1package com.***.widget;
      2
      3//: SoftHashMap.java 
      4import java.util.*
      5import java.lang.ref.*
      6
      7import android.util.Log;
      8
      9public class SoftHashMap extends AbstractMap 
     10  /** The internal HashMap that will hold the SoftReference. */ 
     11  private final Map hash = new HashMap(); 
     12  /** The number of "hard" references to hold internally. */ 
     13  private final int HARD_SIZE; 
     14  /** The FIFO list of hard references, order of last access. */ 
     15  private final LinkedList hardCache = new LinkedList(); 
     16  /** Reference queue for cleared SoftReference objects. */ 
     17  private ReferenceQueue queue = new ReferenceQueue(); 
     18
     19  //Strong Reference number
     20  public SoftHashMap() this(100); } 
     21  public SoftHashMap(int hardSize) { HARD_SIZE = hardSize; } 
     22  
     23
     24  public Object get(Object key) 
     25    Object result = null
     26    // We get the SoftReference represented by that key 
     27    SoftReference soft_ref = (SoftReference)hash.get(key); 
     28    if (soft_ref != null
     29      // From the SoftReference we get the value, which can be 
     30      // null if it was not in the map, or it was removed in 
     31      // the processQueue() method defined below 
     32      result = soft_ref.get(); 
     33      if (result == null
     34        // If the value has been garbage collected, remove the 
     35        // entry from the HashMap. 
     36        hash.remove(key); 
     37      }
     else 
     38        // We now add this object to the beginning of the hard 
     39        // reference queue.  One reference can occur more than 
     40        // once, because lookups of the FIFO queue are slow, so 
     41        // we don't want to search through it each time to remove 
     42        // duplicates. 
     43          //keep recent use object in memory
     44        hardCache.addFirst(result); 
     45        if (hardCache.size() > HARD_SIZE) 
     46          // Remove the last entry if list longer than HARD_SIZE 
     47          hardCache.removeLast(); 
     48        }
     
     49      }
     
     50    }
     
     51    return result; 
     52  }
     
     53
     54  /** We define our own subclass of SoftReference which contains 
     55   not only the value but also the key to make it easier to find 
     56   the entry in the HashMap after it's been garbage collected. */
     
     57  private static class SoftValue extends SoftReference 
     58    private final Object key; // always make data member final 
     59    /** Did you know that an outer class can access private data 
     60     members and methods of an inner class?  I didn't know that! 
     61     I thought it was only the inner class who could access the 
     62     outer class's private information.  An outer class can also 
     63     access private members of an inner class inside its inner 
     64     class. */
     
     65    private SoftValue(Object k, Object key, ReferenceQueue q) 
     66      super(k, q); 
     67      this.key = key; 
     68    }
     
     69  }
     
     70
     71  /** Here we go through the ReferenceQueue and remove garbage 
     72   collected SoftValue objects from the HashMap by looking them 
     73   up using the SoftValue.key data member. */
     
     74  public void processQueue() 
     75    SoftValue sv; 
     76    while ((sv = (SoftValue)queue.poll()) != null
     77        if(sv.get()== null){
     78            Log.e("processQueue""null");
     79        }
    else{
     80            Log.e("processQueue""Not null");
     81        }

     82      hash.remove(sv.key); // we can access private data!
     83      Log.e("SoftHashMap""release " + sv.key);
     84    }
     
     85  }
     
     86  /** Here we put the key, value pair into the HashMap using 
     87   a SoftValue object. */
     
     88  public Object put(Object key, Object value) 
     89    processQueue(); // throw out garbage collected values first 
     90    Log.e("SoftHashMap""put into " + key);
     91    return hash.put(key, new SoftValue(value, key, queue)); 
     92  }
     
     93  public Object remove(Object key) 
     94    processQueue(); // throw out garbage collected values first 
     95    return hash.remove(key); 
     96  }
     
     97  public void clear() 
     98    hardCache.clear(); 
     99    processQueue(); // throw out garbage collected values 
    100    hash.clear(); 
    101  }
     
    102  public int size() 
    103    processQueue(); // throw out garbage collected values first 
    104    return hash.size(); 
    105  }
     
    106  public Set entrySet() 
    107    // no, no, you may NOT do that!!! GRRR 
    108    throw new UnsupportedOperationException(); 
    109  }
     
    110}
     
    111
    112
    113


     

    參考文獻(xiàn)

    Java 內(nèi)存管理原理、內(nèi)存泄漏實(shí)例及解決方案研究

    Java中的強(qiáng)引用、軟引用、弱引用和虛引用

    垃圾回收與強(qiáng)引用,軟引用,弱引用,幻引用的關(guān)系

    posted on 2011-02-23 21:34 zh.weir 閱讀(13419) 評(píng)論(1)  編輯  收藏 所屬分類(lèi): Java的深入理解

    評(píng)論

    # re: Java內(nèi)存泄露的理解與解決 2014-08-14 13:57 memleak.in

    不錯(cuò),學(xué)習(xí) http://memleak.in  回復(fù)  更多評(píng)論   

    公告

    大家好!歡迎光臨我的 Android 技術(shù)博客!



    本博客旨在交流與 Android 操作系統(tǒng)相關(guān)的各種技術(shù)及信息。

    博客內(nèi)的文章會(huì)盡量以開(kāi)源的形式提供給大家,希望我們能相互交流,共同提高!

    有不足之處,請(qǐng)不吝賜教!

    我的郵箱:zh.weir@gmail.com
    我的新浪微博:@囧虎張建偉

     

    導(dǎo)航

    <2011年2月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272812345
    6789101112

    統(tǒng)計(jì)

    • 隨筆 - 18
    • 文章 - 1
    • 評(píng)論 - 290
    • 引用 - 0

    留言簿(19)

    隨筆分類(lèi)(24)

    隨筆檔案(18)

    文章檔案(1)

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 国产成人精品日本亚洲| 亚洲精品中文字幕无码A片老| 视频一区二区三区免费观看| 最好看的中文字幕2019免费| 狠狠亚洲狠狠欧洲2019| 亚洲一区二区观看播放| 中文字幕免费高清视频| 国产成人毛片亚洲精品| 亚洲人成电影网站色www| 最近2018中文字幕免费视频| 国产亚洲av人片在线观看| 亚洲AV无码专区在线观看成人| 最近中文字幕电影大全免费版| 日本亚洲国产一区二区三区| 国产亚洲精品欧洲在线观看| 免费电视剧在线观看| 久久精品国产亚洲AV香蕉| 成在线人免费无码高潮喷水| 丁香亚洲综合五月天婷婷| 亚洲日韩中文字幕一区| 亚洲免费观看在线视频| 久久噜噜噜久久亚洲va久| 一级成人a免费视频| 日日夜夜精品免费视频| 亚洲深深色噜噜狠狠网站| 2022久久国产精品免费热麻豆| 精品国产_亚洲人成在线高清 | ASS亚洲熟妇毛茸茸PICS| 一级毛片成人免费看免费不卡 | 亚洲成A∨人片在线观看不卡| 青青青视频免费观看| 国产男女猛烈无遮挡免费视频网站| 亚洲国产精品午夜电影| 91精品视频在线免费观看| 国产国拍亚洲精品mv在线观看 | 最近中文字幕无免费视频| 亚洲国产成人久久精品影视| 免费萌白酱国产一区二区三区| 久久亚洲国产精品123区| 免费国产高清毛不卡片基地| 免费国产一级特黄久久|