3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java并发核心知识体系精讲_JVM核心知识体系

發(fā)布時(shí)間:2023/12/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java并发核心知识体系精讲_JVM核心知识体系 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
作者:林振華
來源:編程原理

1.問題

  • 如何理解類文件結(jié)構(gòu)布局?
  • 如何應(yīng)用類加載器的工作原理進(jìn)行將應(yīng)用輾轉(zhuǎn)騰挪?
  • 熱部署與熱替換有何區(qū)別,如何隔離類沖突?
  • JVM如何管理內(nèi)存,有何內(nèi)存淘汰機(jī)制?
  • JVM執(zhí)行引擎的工作機(jī)制是什么?
  • JVM調(diào)優(yōu)應(yīng)該遵循什么原則,使用什么工具?
  • JPDA架構(gòu)是什么,如何應(yīng)用代碼熱替換?
  • JVM字節(jié)碼增強(qiáng)技術(shù)有哪些?
  • 2.關(guān)鍵詞

    類結(jié)構(gòu),類加載器,加載,鏈接,初始化,雙親委派,熱部署,隔離,堆,棧,方法區(qū),計(jì)數(shù)器,內(nèi)存回收,執(zhí)行引擎,調(diào)優(yōu)工具,JVMTI,JDWP,JDI,熱替換,字節(jié)碼,ASM,CGLIB,DCEVM

    3.全文概要

    作為三大工業(yè)級(jí)別語言之一的JAVA如此受企業(yè)青睞有加,離不開她背后JVM的默默復(fù)出。只是由于JAVA過于成功以至于我們常常忘了JVM平臺(tái)上還運(yùn)行著像Clojure/Groovy/Kotlin/Scala/JRuby/Jython這樣的語言。我們享受著JVM帶來跨平臺(tái)“一次編譯到處執(zhí)行”臺(tái)的便利和自動(dòng)內(nèi)存回收的安逸。

    本文從JVM的最小元素類的結(jié)構(gòu)出發(fā),介紹類加載器的工作原理和應(yīng)用場(chǎng)景,思考類加載器存在的意義。進(jìn)而描述JVM邏輯內(nèi)存的分布和管理方式,同時(shí)列舉常用的JVM調(diào)優(yōu)工具和使用方法,最后介紹高級(jí)特性JDPA框架和字節(jié)碼增強(qiáng)技術(shù),實(shí)現(xiàn)熱替換。從微觀到宏觀,從靜態(tài)到動(dòng)態(tài),從基礎(chǔ)到高階介紹JVM的知識(shí)體系。

    4.類的裝載

    4.1類的結(jié)構(gòu)

    我們知道不只JAVA文本文件,像Clojure/Groovy/Kotlin/Scala這些文本文件也同樣會(huì)經(jīng)過JDK的編譯器編程成class文件。進(jìn)入到JVM領(lǐng)域后,其實(shí)就跟JAVA沒什么關(guān)系了,JVM只認(rèn)得class文件,那么我們需要先了解class這個(gè)黑箱里面包含的是什么東西。

    JVM規(guī)范嚴(yán)格定義了CLASS文件的格式,有嚴(yán)格的數(shù)據(jù)結(jié)構(gòu),下面我們可以觀察一個(gè)簡(jiǎn)單CLASS文件包含的字段和數(shù)據(jù)類型。

    詳細(xì)的描述我們可以從JVM規(guī)范說明書里面查閱類文件格式,類的整體布局如下圖展示的。

    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

    在我的理解,我想把每個(gè)CLASS文件類別成一個(gè)一個(gè)的數(shù)據(jù)庫,里面包含的常量池/類索引/屬性表集合就像數(shù)據(jù)庫的表,而且表之間也有關(guān)聯(lián),常量池則存放著其他表所需要的所有字面量。了解完類的數(shù)據(jù)結(jié)構(gòu)后,我們需要來觀察JVM是如何使用這些從硬盤上或者網(wǎng)絡(luò)傳輸過來的CLASS文件。

    4.2加載機(jī)制

    4.2.1類的入口

    在我們探究JVM如何使用CLASS文件之前,我們快速回憶一下編寫好的C語言文件是如何執(zhí)行的?我們從C的HelloWorld入手看看先。

    編輯完保存為hello.c文本文件,然后安裝gcc編譯器(GNU C/C++)

    這個(gè)過程就是gcc編譯器將hello.c文本文件編譯成機(jī)器指令集,然后讀取到內(nèi)存直接在計(jì)算機(jī)的CPU運(yùn)行。從操作系統(tǒng)層面看的話,就是一個(gè)進(jìn)程的啟動(dòng)到結(jié)束的生命周期。

    下面我們看JAVA是怎么運(yùn)行的。學(xué)習(xí)JAVA開發(fā)的第一件事就是先下載JDK安裝包,安裝完配置好環(huán)境變量,然后寫一個(gè)名字為helloWorld的類,然后編譯執(zhí)行,我們來觀察一下發(fā)生了什么事情?

    先看源碼,有夠簡(jiǎn)單了吧。

    編譯執(zhí)行

    對(duì)比C語言在命令行直接運(yùn)行編譯后的a.out二進(jìn)制文件,JAVA的則是在命令行執(zhí)行java classFile,從命令的區(qū)別我們知道操作系統(tǒng)啟動(dòng)的是java進(jìn)程,而HelloWorld類只是命令行的入?yún)?#xff0c;在操作系統(tǒng)來看java也就是一個(gè)普通的應(yīng)用進(jìn)程而已,而這個(gè)進(jìn)程就是JVM的執(zhí)行形態(tài)(JVM靜態(tài)就是硬盤里JDK包下的二進(jìn)制文件集合)。

    學(xué)習(xí)過JAVA的都知道入口方法是public static void main(String[] args),缺一不可,那我猜執(zhí)行java命令時(shí)JVM對(duì)該入口方法做了唯一驗(yàn)證,通過了才允許啟動(dòng)JVM進(jìn)程,下面我們來看這個(gè)入口方法有啥特點(diǎn)。

    去掉public限定

    說明入口方法需要被public修飾,當(dāng)然JVM調(diào)用main方法是底層的JNI方法調(diào)用不受修飾符影響。

    去掉static限定

    我們是從類對(duì)象調(diào)用而不是類創(chuàng)建的對(duì)象才調(diào)用,索引需要靜態(tài)修飾

    返回類型改為int

    void返回類型讓JVM調(diào)用后無需關(guān)心調(diào)用者的使用情況,執(zhí)行完就停止,簡(jiǎn)化JVM的設(shè)計(jì)。

    方法簽名改為main1

    這個(gè)我也不清楚,可能是約定俗成吧,畢竟C/C++也是用main方法的。

    說了這么多main方法的規(guī)則,其實(shí)我們關(guān)心的只有兩點(diǎn):

    • HelloWorld類是如何被JVM使用的
    • HelloWorld類里面的main方法是如何被執(zhí)行的
    關(guān)于JVM如何使用HelloWorld下文我們會(huì)詳細(xì)講到。

    我們知道JVM是由C/C++語言實(shí)現(xiàn)的,那么JVM跟CLASS打交道則需要JNI(Java Native Interface)這座橋梁,當(dāng)我們?cè)诿钚袌?zhí)行java時(shí),由C/C++實(shí)現(xiàn)的java應(yīng)用通過JNI找到了HelloWorld里面符合規(guī)范的main方法,然后開始調(diào)用。我們來看下java命令的源碼就知道了

    4.2.2類加載器

    上一節(jié)我們留了一個(gè)核心的環(huán)節(jié),就是JVM在執(zhí)行類的入口之前,首先得找到類再然后再把類裝到JVM實(shí)例里面,也即是JVM進(jìn)程維護(hù)的內(nèi)存區(qū)域內(nèi)。

    我們當(dāng)然知道是一個(gè)叫做類加載器的工具把類加載到JVM實(shí)例里面,拋開細(xì)節(jié)從操作系統(tǒng)層面觀察,那么就是JVM實(shí)例在運(yùn)行過程中通過IO從硬盤或者網(wǎng)絡(luò)讀取CLASS二進(jìn)制文件,然后在JVM管轄的內(nèi)存區(qū)域存放對(duì)應(yīng)的文件。我們目前還不知道類加載器的實(shí)現(xiàn),但是我們從功能上判斷無非就是讀取文件到內(nèi)存,這個(gè)是很普通也很簡(jiǎn)單的操作。

    如果類加載器是C/C++實(shí)現(xiàn)的話,那么大概就是如下代碼就可以實(shí)現(xiàn)

    char *fgets( char *buf, int n, FILE *fp );

    如果是JAVA實(shí)現(xiàn),那么也很簡(jiǎn)單

    InputStream f = new FileInputStream("theory/jvm/HelloWorld.class");

    從操作系統(tǒng)層面看的話,如果只是加載,以上代碼就足以把類文件加載到JVM內(nèi)存里面了。但是結(jié)果就是亂糟糟的把一堆毫無秩序的類文件往內(nèi)存里面扔,沒有良好的管理也沒法用,所以需要我們需要設(shè)計(jì)一套規(guī)則來管理存放內(nèi)存里面的CLASS文件,我們稱為類加載的設(shè)計(jì)模式或者類加載機(jī)制,這個(gè)下文會(huì)重點(diǎn)解釋。

    根據(jù)官網(wǎng)的定義A class loader is an object that is responsible for loading classes. 類加載器就是負(fù)責(zé)加載類的。我們知道啟動(dòng)JVM的時(shí)候會(huì)把JRE默認(rèn)的一些類加載到內(nèi)存,這部分類使用的加載器是JVM默認(rèn)內(nèi)置的由C/C++實(shí)現(xiàn)的,比如我們上文加載的HelloWorld.class。

    但是內(nèi)置的類加載器有明確的范圍限定,也就是只能加載指定路徑下的jar包(類文件的集合)。如果只是加載JRE的類,那可玩的花樣就少很多,JRE只是提供了底層所需的類,更多的業(yè)務(wù)需要我們從外部加載類來支持,所以我們需要指定新的規(guī)則,以方便我們加載外部路徑的類文件。

    系統(tǒng)默認(rèn)加載器


    Bootstrap class loader

    作用:啟動(dòng)類加載器,加載JDK核心類

    類加載器:C/C++實(shí)現(xiàn)

    類加載路徑: /jre/lib

    URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar ... /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar

    實(shí)現(xiàn)原理:本地方法由C++實(shí)現(xiàn)


    Extensions class loader

    作用:擴(kuò)展類加載器,加載JAVA擴(kuò)展類庫。

    類加載器:JAVA實(shí)現(xiàn)

    類加載路徑:/jre/lib/ext

    實(shí)現(xiàn)原理:擴(kuò)展類加載器ExtClassLoader本質(zhì)上也是URLClassLoader

    Launcher.java


    System class loader

    作用:系統(tǒng)類加載器,加載應(yīng)用指定環(huán)境變量路徑下的類

    類加載器:sun.misc.Launcher$AppClassLoader

    類加載路徑:-classpath下面的所有類

    實(shí)現(xiàn)原理:系統(tǒng)類加載器AppClassLoader本質(zhì)上也是URLClassLoader

    Launcher.java


    通過上文運(yùn)行HelloWorld我們知道JVM系統(tǒng)默認(rèn)加載的類大改是1560個(gè),如下圖

    自定義類加載器

    內(nèi)置類加載器只加載了最少需要的核心JAVA基礎(chǔ)類和環(huán)境變量下的類,但是我們應(yīng)用往往需要依賴第三方中間件來完成額外的業(yè)務(wù),那么如何把它們的類加載進(jìn)來就顯得格外重要了。

    幸好JVM提供了自定義類加載器,可以很方便的完成自定義操作,最終目的也是把外部的類文件加載到JVM內(nèi)存。通過繼承ClassLoader類并且復(fù)寫findClass和loadClass方法就可以達(dá)到自定義獲取CLASS文件的目的。

    首先我們看ClassLoader的核心方法loadClass

    通過復(fù)寫loadClass方法,我們甚至可以讀取一份加了密的文件,然后在內(nèi)存里面解密,這樣別人反編譯你的源碼也沒用,因?yàn)閏lass是經(jīng)過加密的,也就是理論上我們通過自定義類加載器可以做到為所欲為,但是有個(gè)重要的原則下文介紹類加載器設(shè)計(jì)模式會(huì)提到。

    一下給出一個(gè)自定義類加載器極簡(jiǎn)的案例,來說明自定義類加載器的實(shí)現(xiàn)。

    package com.zooncool.example.theory.jvm; import java.io.FileInputStream; import static java.lang.System.out;public class ClassIsolationPrinciple {public static void main(String[] args) {try {String className = "com.zooncool.example.theory.jvm.ClassIsolationPrinciple$Demo"; //定義要加載類的全限定名Class<?> class1 = Demo.class; //第一個(gè)類又系統(tǒng)默認(rèn)類加載器加載//第二個(gè)類MyClassLoader為自定義類加載器,自定義的目的是覆蓋加載類的邏輯Class<?> class2 = new MyClassLoader("target/classes").loadClass(className);out.println("-----------------class name-----------------");out.println(class1.getName());out.println(class2.getName());out.println("-----------------classLoader name-----------------");out.println(class1.getClassLoader());out.println(class2.getClassLoader());Demo.example = 1;//這里修改的系統(tǒng)類加載器加載的那個(gè)類的對(duì)象,而自定義加載器加載進(jìn)去的類的對(duì)象保持不變,也即是同時(shí)存在內(nèi)存,但沒有修改example的值。out.println("-----------------field value-----------------");out.println(class1.getDeclaredField("example").get(null));out.println(class2.getDeclaredField("example").get(null));} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}public static class Demo {public static int example = 0;}public static class MyClassLoader extends ClassLoader{private String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}//自定義類加載器繼承了ClassLoader,稱為一個(gè)可以加載類的加載器,同時(shí)覆蓋了loadClass方法,實(shí)現(xiàn)自己的邏輯@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {if(!name.contains("java.lang")){//排除掉加載系統(tǒng)默認(rèn)需要加載的內(nèi)心類,因?yàn)樾╊愔荒苡帜J(rèn)類加載器去加載,第三方加載會(huì)拋異常,具體原因下文解釋byte[] data = new byte[0];try {data = loadByte(name);} catch (Exception e) {e.printStackTrace();}return defineClass(name,data,0,data.length);}else{return super.loadClass(name);}}//把影片的二進(jìn)制類文件讀入內(nèi)存字節(jié)流private byte[] loadByte(String name) throws Exception {name = name.replaceAll(".", "/");String dir = classPath + "/" + name + ".class";FileInputStream fis = new FileInputStream(dir);int len = fis.available();byte[] data = new byte[len];fis.read(data);fis.close();return data;}} }

    執(zhí)行結(jié)果如下,我們可以看到加載到內(nèi)存方法區(qū)的兩個(gè)類的包名+名稱是一樣的,而對(duì)應(yīng)的類加載器卻不一樣,而且輸出被加載類的值也是不一樣的。

    4.2.3設(shè)計(jì)模式

    現(xiàn)有的加載器分為內(nèi)置類加載器和自定義加載器,不管它們是通過C或者JAVA實(shí)現(xiàn)的最終都是為了把外部的CLASS文件加載到JVM內(nèi)存里面。那么我們就需要設(shè)計(jì)一套規(guī)則來管理組織內(nèi)存里面的CLASS文件,下面我們就來介紹下通過這套規(guī)則如何來協(xié)調(diào)好內(nèi)置類加載器和自定義類加載器之間的權(quán)責(zé)。

    我們知道通過自定義類加載器可以干出很多黑科技,但是有個(gè)基本的雷區(qū)就是,不能隨便替代JAVA的核心基礎(chǔ)類,或者說即是你寫了一個(gè)跟核心類一模一樣的類,JVM也不會(huì)使用。

    你想一下,如果為所欲為的你可以把最基礎(chǔ)本的java.lang.Object都換成你自己定義的同名類,然后搞個(gè)后門進(jìn)去,而且JVM還使用的話,那誰還敢用JAVA了是吧,所以我們會(huì)介紹一個(gè)重要的原則,在此之前我們先介紹一下內(nèi)置類加載器和自定義類加載器是如何協(xié)同的。

    雙親委派機(jī)制

    • 定義:某個(gè)特定的類加載器在接到加載類的請(qǐng)求時(shí),首先將加載任務(wù)委托給父類加載器,依次遞歸,如果父類加載器可以完成類加載任務(wù),就成功返回;只有父類加載器無法完成此加載任務(wù)時(shí),才自己去加載。
    • 實(shí)現(xiàn):參考上文loadClass方法的源碼和注釋,通過最多三次遞歸可以到啟動(dòng)類加載器,如果還是找不到這調(diào)用自定義方法。

    • 說明:雙親委派機(jī)制很好理解,目的就是為了不重復(fù)加載已有的類,提高效率,還有就是強(qiáng)制從父類加載器開始逐級(jí)搜索類文件,確保核心基礎(chǔ)類優(yōu)先加載。下面介紹的是破壞雙親委派機(jī)制,了解為什么要破壞這種看似穩(wěn)固的雙親委派機(jī)制。

    破壞委派機(jī)制

    • 定義:打破類加載自上而上委托的約束。
    • 實(shí)現(xiàn):
      1、繼承ClassLoader并且重寫loadClass方法體,覆蓋依賴上層類加載器的邏輯;
      2、”啟動(dòng)類加載器”可以指定“線程上下文類加載器”為任意類加載器,即是“父類加載器”委托“子類加載器”去加載不屬于它加載范圍的類文件;
    • 說明:雙親委派機(jī)制的好處上面我們已經(jīng)提過了,但是由于一些歷史原因(JDK1.2加上雙親委派機(jī)制前的JDK1.1就已經(jīng)存在,為了向前兼容不得不開這個(gè)后門讓1.2版本的類加載器擁有1.1隨意加載的功能)。還有就是JNDI的服務(wù)調(diào)用機(jī)制,例如調(diào)用JDBC需要從外部加載相關(guān)類到JVM實(shí)例的內(nèi)存空間。
    介紹完內(nèi)置類加載器和自定義類加載器的協(xié)同關(guān)系后,我們要重點(diǎn)強(qiáng)調(diào)上文提到的重要原則。

    唯一標(biāo)識(shí)

    • 定義:JVM實(shí)例由類加載器+類的全限定包名和類名組成類的唯一標(biāo)志。
    • 實(shí)現(xiàn):加載類的時(shí)候,JVM 判斷類是否來自相同的加載器,如果相同而且全限定名則直接返回內(nèi)存已有的類。
    • 說明:上文我們提到如何防止相同類的后門問題,有了這個(gè)黃金法則,即使相同的類路徑和類,但是由于是由自定義類加載器加載的,即使編譯通過能被加載到內(nèi)存,也無法使用,因?yàn)镴VM核心類是由內(nèi)置類加載器加載標(biāo)志和使用的,從而保證了JVM的安全加載。通過緩存類加載器和全限定包名和類名作為類唯一索引,加載重復(fù)類則拋異常提示”attempted duplicate class definition for name”。
    • 原理:雙親委派機(jī)制父類檢查緩存,源碼我們介紹loadClass方法的時(shí)候已經(jīng)講過,破壞雙親委派的自定義類加載器在加載類二進(jìn)制字節(jié)碼后需要調(diào)用defineClass方法,而該方法同樣會(huì)從JVM方法區(qū)檢索緩存類,存在的話則提示重復(fù)定義。

    4.2.4加載過程

    至此我們已經(jīng)深刻認(rèn)識(shí)到類加載器的工作原理及其存在的意義,下面我們將介紹類從外部介質(zhì)加載使用到卸載整個(gè)閉環(huán)的生命周期。

    加載

    上文花了不少的篇幅說明了類的結(jié)構(gòu)和類是如何被加載到JVM內(nèi)存里面的,那究竟什么時(shí)候JVM才會(huì)觸發(fā)類加載器去加載外部的CLASS文件呢?通常有如下四種情況會(huì)觸發(fā)到:

    • 顯式字節(jié)碼指令集(new/getstatic/putstatic/invokestatic):對(duì)應(yīng)的場(chǎng)景就是創(chuàng)建對(duì)象或者調(diào)用到類文件的靜態(tài)變量/靜態(tài)方法/靜態(tài)代碼塊
    • 反射:通過對(duì)象反射獲取類對(duì)象時(shí)
    • 繼承:創(chuàng)建子類觸發(fā)父類加載
    • 入口:包含main方法的類首先被加載

    JVM只定了類加載器的規(guī)范,但卻不明確規(guī)定類加載器的目標(biāo)文件,把加載的具體邏輯充分交給了用戶,包括重硬盤加載的CLASS類到網(wǎng)絡(luò),中間文件等,只要加載進(jìn)去內(nèi)存的二進(jìn)制數(shù)據(jù)流符合JVM規(guī)定的格式,都是合法的。

    鏈接

    類加載器加載完類到JVM實(shí)例的指定內(nèi)存區(qū)域(方法區(qū)下文會(huì)提到)后,是使用前會(huì)經(jīng)過驗(yàn)證,準(zhǔn)備解析的階段。

    • 驗(yàn)證:主要包含對(duì)類文件對(duì)應(yīng)內(nèi)存二進(jìn)制數(shù)據(jù)的格式、語義關(guān)聯(lián)、語法邏輯和符合引用的驗(yàn)證,如果驗(yàn)證不通過則跑出VerifyError的錯(cuò)誤。但是該階段并非強(qiáng)制執(zhí)行,可以通過-Xverify:none來關(guān)閉,提高性能。
    • 準(zhǔn)備:但我們驗(yàn)證通過時(shí),內(nèi)存的方法區(qū)存放的是被“緊密壓縮”的數(shù)據(jù)段,這個(gè)時(shí)候會(huì)對(duì)static的變量進(jìn)行內(nèi)存分配,也就是擴(kuò)展內(nèi)存段的空間,為該變量匹配對(duì)應(yīng)類型的內(nèi)存空間,但還未初始化數(shù)據(jù),也就是0或者null的值。
    • 解析:我們知道類的數(shù)據(jù)結(jié)構(gòu)類似一個(gè)數(shù)據(jù)庫,里面多張不同類型的“表”緊湊的挨在一起,最大的節(jié)省類占用的空間。多數(shù)表都會(huì)應(yīng)用到常量池表里面的字面量,這個(gè)時(shí)候就是把引用的字面量轉(zhuǎn)化為直接的變量空間。比如某一個(gè)復(fù)雜類變量字面量在類文件里只占2個(gè)字節(jié),但是通過常量池引用的轉(zhuǎn)換為實(shí)際的變量類型,需要占用32個(gè)字節(jié)。所以經(jīng)過解析階段后,類在方法區(qū)占用的空間就會(huì)膨脹,長(zhǎng)得更像一個(gè)”類“了。

    初始化

    方法區(qū)經(jīng)過解析后類已經(jīng)為各個(gè)變量占好坑了,初始化就是把變量的初始值和構(gòu)造方法的內(nèi)容初始化到變量的空間里面。這時(shí)候我們介質(zhì)的類二進(jìn)制文件所定義的內(nèi)容,已經(jīng)完全被“翻譯”方法區(qū)的某一段內(nèi)存空間了。萬事俱備只待使用了。

    使用

    使用呼應(yīng)了我們加載類的觸發(fā)條件,也即是觸發(fā)類加載的條件也是類應(yīng)用的條件,該操作會(huì)在初始化完成后進(jìn)行。

    卸載

    我們知道JVM有垃圾回收機(jī)制(下文會(huì)詳細(xì)介紹),不需要我們操心,總體上有三個(gè)條件會(huì)觸發(fā)垃圾回收期清理方法區(qū)的空間:

    • 類對(duì)應(yīng)實(shí)例被回收
    • 類對(duì)應(yīng)加載器被回收
    • 類無反射引用

    本節(jié)結(jié)束我們已經(jīng)對(duì)整個(gè)類的生命周期爛熟于胸了,下面我們來介紹類加載機(jī)制最核心的幾種應(yīng)用場(chǎng)景,來加深對(duì)類加載技術(shù)的認(rèn)識(shí)。

    4.3應(yīng)用場(chǎng)景

    通過前文的剖析我們已經(jīng)非常清楚類加載器的工作原理,那么我們?cè)撊绾卫妙惣虞d器的特點(diǎn),最大限度的發(fā)揮它的作用呢?

    4.3.1熱部署

    背景

    熱部署這個(gè)詞匯我們經(jīng)常聽說也經(jīng)常提起,但是卻很少能夠準(zhǔn)確的描述出它的定義。說到熱部署我們第一時(shí)間想到的可能是生產(chǎn)上的機(jī)器更新代碼后無需重啟應(yīng)用容器就能更新服務(wù),這樣的好處就是服務(wù)無需中斷可持續(xù)運(yùn)行,那么與之對(duì)應(yīng)的冷部署當(dāng)然就是要重啟應(yīng)用容器實(shí)例了。

    還有可能會(huì)想到的是使用IDE工具開發(fā)時(shí)不需要重啟服務(wù),修改代碼后即時(shí)生效,這看起來可能都是服務(wù)無需重啟,但背后的運(yùn)行機(jī)制確截然不同,首先我們需要對(duì)熱部署下一個(gè)準(zhǔn)確的定義。

    熱部署(Hot Deployment):熱部署是應(yīng)用容器自動(dòng)更新應(yīng)用的一種能力。

    首先熱部署應(yīng)用容器擁有的一種能力,這種能力是容器本身設(shè)計(jì)出來的,跟具體的IDE開發(fā)工具無關(guān)。而且熱部署無需重啟服務(wù)器,應(yīng)用可以保持用戶態(tài)不受影響。上文提到我們開發(fā)環(huán)境使用IDE工具通常也可以設(shè)置無需重啟的功能,有別于熱部署的是此時(shí)我們應(yīng)用的是JVM的本身附帶的熱替換能力(HotSwap)。

    熱部署和熱替換是兩個(gè)完全不同概念,在開發(fā)過程中也常常相互配合使用,導(dǎo)致我們很多人經(jīng)常混淆概念,所以接下來我們來剖析熱部署的實(shí)現(xiàn)原理,而熱替換的高級(jí)特性我們會(huì)在下文字節(jié)碼增強(qiáng)的章節(jié)中介紹。

    原理

    從熱部署的定義我們知道它是應(yīng)用容器蘊(yùn)含的一項(xiàng)能力,要達(dá)到的目的就是在服務(wù)沒有重啟的情況下更新應(yīng)用,也就是把新的代碼編譯后產(chǎn)生的新類文件替換掉內(nèi)存里的舊類文件。

    結(jié)合前文我們介紹的類加載器特性,這似乎也不是很難,分兩步應(yīng)該可以完成。由于同一個(gè)類加載器只能加載一次類文件,那么新增一個(gè)類加載器把新的類文件加載進(jìn)內(nèi)存。此時(shí)內(nèi)存里面同時(shí)存在新舊的兩個(gè)類(類名路徑一樣,但是類加載器不一樣),要做的就是如何使用新的類,同時(shí)卸載舊的類及其對(duì)象,完成這兩步其實(shí)也就是熱部署的過程了。也即是通過使用新的類加載器,重新加載應(yīng)用的類,從而達(dá)到新代碼熱部署。

    實(shí)現(xiàn)

    理解了熱部署的工作原理,下面通過一系列極簡(jiǎn)的例子來一步步實(shí)現(xiàn)熱部署,為了方便讀者演示,以下例子我盡量都在一個(gè)java文件里面完成所有功能,運(yùn)行的時(shí)候復(fù)制下去就可以跑起來。

    實(shí)現(xiàn)自定義類加載器

    參考4.2.2中自定義類加載器區(qū)別系統(tǒng)默認(rèn)加載器的案例,從該案例實(shí)踐中我們可以將相同的類(包名+類名),不同”版本“(類加載器不一樣)的類同時(shí)加載進(jìn)JVM內(nèi)存方法區(qū)。

    替換自定義類加載器

    既然一個(gè)類通過不同類加載器可以被多次加載到JVM內(nèi)存里面,那么類的經(jīng)過修改編譯后再加載進(jìn)內(nèi)存。有別于上一步給出的例子只是修改對(duì)象的值,這次我們是直接修改類的內(nèi)容,從應(yīng)用的視角看其實(shí)就是應(yīng)用更新,那如何做到在線程運(yùn)行不中斷的情況下更換新類呢?

    下面給出的也是一個(gè)很簡(jiǎn)單的例子,ClassReloading啟動(dòng)main方法通過死循環(huán)不斷創(chuàng)建類加載器,同時(shí)不斷加載類而且執(zhí)行類的方法。注意new MyClassLoader(“target/classes”)的路徑更加編譯的class路徑來修改,其他直接復(fù)制過去就可以執(zhí)行演示了。

    ClassReloading線程執(zhí)行過程不斷輪流注釋say()和ask()代碼,然后編譯類,觀察程序輸出。

    如下輸出結(jié)果,我們可以看出每一次循環(huán)調(diào)用都新創(chuàng)建一個(gè)自定義類加載器,然后通過反射創(chuàng)建對(duì)象調(diào)用方法,在修改代碼編譯后,新的類就會(huì)通過反射創(chuàng)建對(duì)象執(zhí)行新的代碼業(yè)務(wù),而主線程則一直沒有中斷運(yùn)行。

    讀到這里,其實(shí)我們已經(jīng)基本觸達(dá)了熱部署的本質(zhì)了,也就是實(shí)現(xiàn)了手動(dòng)無中斷部署。但是缺點(diǎn)就是需要我們手動(dòng)編譯代碼,而且內(nèi)存不斷新增類加載器和對(duì)象,如果速度過快而且頻繁更新,還可能造成堆溢出,下一個(gè)例子我們將增加一些機(jī)制來保證舊的類和對(duì)象能被垃圾收集器自動(dòng)回收。

    回收自定義類加載器

    通常情況下類加載器會(huì)持有該加載器加載過的所有類的引用,所有如果類是經(jīng)過系統(tǒng)默認(rèn)類加載器加載的話,那就很難被垃圾收集器回收,除非符合根節(jié)點(diǎn)不可達(dá)原則才會(huì)被回收。

    下面繼續(xù)給出一個(gè)很簡(jiǎn)單的例子,我們知道ClassReloading只是不斷創(chuàng)建新的類加載器來加載新類從而更新類的方法。下面的例子我們模擬WEB應(yīng)用,更新整個(gè)應(yīng)用的上下文Context。

    下面代碼本質(zhì)上跟上個(gè)例子的功能是一樣的,只不過我們通過加載Model層、DAO層和Service層來模擬web應(yīng)用,顯得更加真實(shí)。

    package com.zooncool.example.theory.jvm; import java.io.FileInputStream; import java.lang.reflect.InvocationTargetException; //應(yīng)用上下文熱加載 public class ContextReloading {public static void main(String[] args)throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException,InvocationTargetException, InterruptedException {for (;;){Object context = newContext();//創(chuàng)建應(yīng)用上下文invokeContext(context);//通過上下文對(duì)象context調(diào)用業(yè)務(wù)方法Thread.sleep(5000);}}//創(chuàng)建應(yīng)用的上下文,context是整個(gè)應(yīng)用的GC roots,創(chuàng)建完返回對(duì)象之前調(diào)用init()初始化對(duì)象public static Object newContext()throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException,InvocationTargetException {String className = "com.zooncool.example.theory.jvm.ContextReloading$Context";//通過自定義類加載器加載Context類Class<?> contextClass = new MyClassLoader("target/classes").loadClass(className);Object context = contextClass.newInstance();//通過反射創(chuàng)建對(duì)象contextClass.getDeclaredMethod("init").invoke(context);//通過反射調(diào)用初始化方法init()return context;}//業(yè)務(wù)方法,調(diào)用context的業(yè)務(wù)方法showUser()public static void invokeContext(Object context)throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {context.getClass().getDeclaredMethod("showUser").invoke(context);}public static class Context{private UserService userService = new UserService();public String showUser(){return userService.getUserMessage();}//初始化對(duì)象public void init(){UserDao userDao = new UserDao();userDao.setUser(new User());userService.setUserDao(userDao);}}public static class UserService{private UserDao userDao;public String getUserMessage(){return userDao.getUserName();}public void setUserDao(UserDao userDao) {this.userDao = userDao;}}public static class UserDao{private User user;public String getUserName(){//關(guān)鍵操作,運(yùn)行main方法后切換下面方法,編譯后下一次調(diào)用生效return user.getName();//return user.getFullName();}public void setUser(User user) {this.user = user;}}public static class User{private String name = "lucy";private String fullName = "hank.lucy";public String getName() {System.out.println("my name is " + name);return name;}public String getFullName() {System.out.println("my full name is " + fullName);return name;}}//跟之前的類加載器一模一樣,可以略過public static class MyClassLoader extends ClassLoader{...} }

    輸出結(jié)果跟上一個(gè)例子相似,可以自己運(yùn)行試試。我們更新業(yè)務(wù)方法編譯通過后,無需重啟main方法,新的業(yè)務(wù)就能生效,而且也解決了舊類卸載的核心問題,因?yàn)閏ontext的應(yīng)用對(duì)象的跟節(jié)點(diǎn),context是由我們自定義類加載器所加載,由于User/Dao/Service都是依賴context,所以其類也是又自定義類加載器所加載。

    根據(jù)GC roots原理,在創(chuàng)建新的自定義類加載器之后,舊的類加載器已經(jīng)沒有任何引用鏈可訪達(dá),符合GC回收規(guī)則,將會(huì)被GC收集器回收釋放內(nèi)存。至此已經(jīng)完成應(yīng)用熱部署的流程,但是細(xì)心的朋友可能會(huì)發(fā)現(xiàn),我們熱部署的策略是整個(gè)上下文context都替換成新的,那么用戶的狀態(tài)也將無法保留。而實(shí)際情況是我們只需要?jiǎng)討B(tài)更新某些模塊的功能,而不是全局。

    這個(gè)其實(shí)也好辦,就是我們從業(yè)務(wù)上把需要熱部署的由自定義類加載器加載,而持久化的類資源則由系統(tǒng)默認(rèn)類加載器去完成。

    自動(dòng)加載類加載器

    其實(shí)設(shè)計(jì)到代碼設(shè)計(jì)優(yōu)雅問題,基本上我們拿出設(shè)計(jì)模式23章經(jīng)對(duì)號(hào)入座基本可以解決問題,畢竟這是前人經(jīng)過千萬實(shí)踐錘煉出來的軟件構(gòu)建內(nèi)功心法。

    那么針對(duì)我們熱部署的場(chǎng)景,如果想把熱部署細(xì)節(jié)封裝出來,那代理模式無疑是最符合要求的,也就是咱們弄出個(gè)代理對(duì)象來面向用戶,把類加載器的更替,回收,隔離等細(xì)節(jié)都放在代理對(duì)象里面完成,而對(duì)于用戶來說是透明無感知的,那么終端用戶體驗(yàn)起來就是純粹的熱部署了。

    至于如何實(shí)現(xiàn)自動(dòng)熱部署,方式也很簡(jiǎn)單,監(jiān)聽我們部署的目錄,如果文件時(shí)間和大小發(fā)生變化,則判斷應(yīng)用需要更新,這時(shí)候就觸發(fā)類加載器的創(chuàng)建和舊對(duì)象的回收,這個(gè)時(shí)候也可以引入觀察者模式來實(shí)現(xiàn)。由于篇幅限制,本例子就留給讀者朋友自行設(shè)計(jì),相信也是不難完成的。

    案例

    上一節(jié)我們深入淺出的從自定義類加載器的開始引入,到實(shí)現(xiàn)多個(gè)類加載器加載同個(gè)類文件,最后完成舊類加載器和對(duì)象的回收,整個(gè)流程闡述了熱部署的實(shí)現(xiàn)細(xì)節(jié)。那么這一節(jié)我們介紹現(xiàn)有實(shí)現(xiàn)熱部署的通用解決方案,本質(zhì)就是對(duì)上文原理的實(shí)現(xiàn),加上性能和設(shè)計(jì)上的優(yōu)化,注意本節(jié)我們應(yīng)用的只是類加載器的技術(shù),后面章節(jié)還會(huì)介紹的字節(jié)碼層面的底層操作技術(shù)。

    OSGI

    OSGI(Open Service Gateway Initiative)是一套開發(fā)和部署應(yīng)用程序的java框架。我們從官網(wǎng)可以看到OSGI其實(shí)是一套規(guī)范,好比Servlet定義了服務(wù)端對(duì)于處理來自網(wǎng)絡(luò)請(qǐng)求的一套規(guī)范,比如init,service,destroy的生命周期。

    然后我們通過實(shí)行這套規(guī)范來實(shí)現(xiàn)與客戶端的交互,在調(diào)用init初始化完Servlet對(duì)象后通過多線程模式使用service響應(yīng)網(wǎng)絡(luò)請(qǐng)求。如果從響應(yīng)模式比較我們還可以了解下Webflux的規(guī)范,以上兩種都是處理網(wǎng)絡(luò)請(qǐng)求的方式,當(dāng)然你舉例說CGI也是一種處理網(wǎng)絡(luò)請(qǐng)求的規(guī)范,CGI采用的是多進(jìn)程方式來處理網(wǎng)絡(luò)請(qǐng)求,我們暫時(shí)不對(duì)這兩種規(guī)范進(jìn)行優(yōu)劣評(píng)價(jià),只是說明在處理網(wǎng)絡(luò)請(qǐng)求的場(chǎng)景下可以采用不同的規(guī)范來實(shí)現(xiàn)。

    好了現(xiàn)在回到OSGi,有了上面的鋪墊,相信對(duì)我們理解OSGI大有幫助。我們說OSGI首先是一種規(guī)范,既然是規(guī)范我們就要看看都規(guī)范了啥,比如Servlet也是一種規(guī)范,它規(guī)范了生命周期,規(guī)定應(yīng)用容器中WEB-INF/classes目錄或WEB-INF/lib目錄下的jar包才會(huì)被Web容器處理。

    同樣OSGI的實(shí)現(xiàn)框架對(duì)管轄的Bundle下面的目錄組織和文本格式也有嚴(yán)格規(guī)范,更重要的是OSGI對(duì)模塊化架構(gòu)生命周期的管理。而模塊化也不只是把系統(tǒng)拆分成不同的JAR包形成模塊而已,真正的模塊化必須將模塊中類的引入/導(dǎo)出、隱藏、依賴、版本管理貫穿到生命周期管理中去。

    定義:OSGI是脫胎于(OSGI Alliance)技術(shù)聯(lián)盟由一組規(guī)范和對(duì)應(yīng)子規(guī)范共同定義的JAVA動(dòng)態(tài)模塊化技術(shù)。實(shí)現(xiàn)該規(guī)范的OSGI框架(如Apache Felix)使應(yīng)用程序的模塊能夠在本地或者網(wǎng)絡(luò)中實(shí)現(xiàn)端到端的通信,目前已經(jīng)發(fā)布了第7版。OSGI有很多優(yōu)點(diǎn)諸如熱部署,類隔離,高內(nèi)聚,低耦合的優(yōu)勢(shì),但同時(shí)也帶來了性能損耗,而且基于OSGI目前的規(guī)范繁多復(fù)雜,開發(fā)門檻較高。

    組成:執(zhí)行環(huán)境,安全層,模塊層,生命周期層,服務(wù)層,框架API

    核心服務(wù):

    • 事件服務(wù)(Event Admin Service),
    • 包管理服務(wù)(Package Admin Service)
    • 日志服務(wù)(Log Service)
    • 配置管理服務(wù)(Configuration Admin Service)
    • HTTP服務(wù)(HTTP Service)
    • 用戶管理服務(wù)(User Admin Service)
    • 設(shè)備訪問服務(wù)(Device Access Service)
    • IO連接器服務(wù)(IO Connector Service)
    • 聲明式服務(wù)(Declarative Services)
    • 其他OSGi標(biāo)準(zhǔn)服務(wù)

    本節(jié)我們討論的核心是熱部署,所以我們不打算在這里講解全部得OSGI技術(shù),在上文實(shí)現(xiàn)熱部署后我們重點(diǎn)來剖析OSGI關(guān)于熱部署的機(jī)制。至于OSGI模塊化技術(shù)和java9的模塊化的對(duì)比和關(guān)聯(lián),后面有時(shí)間會(huì)開個(gè)專題專門介紹模塊化技術(shù)。

    從類加載器技術(shù)應(yīng)用的角度切入我們知道OSGI規(guī)范也是打破雙親委派機(jī)制,除了框架層面需要依賴JVM默認(rèn)類加載器之外,其他Bundle(OSGI定義的模塊單元)都是由各自的類加載器來加載,而OSGI框架就負(fù)責(zé)模塊生命周期,模塊交互這些核心功能,同時(shí)創(chuàng)建各個(gè)Bundle的類加載器,用于直接加載Bundle定義的jar包。

    由于打破雙親委派模式,Bundle類加載器不再是雙親委派模型中的樹狀結(jié)構(gòu),而是進(jìn)一步發(fā)展為更加復(fù)雜的網(wǎng)狀結(jié)構(gòu)(因?yàn)楦鱾€(gè)Bundle之間有相互依賴關(guān)系),當(dāng)收到類加載請(qǐng)求時(shí),OSGi將按照下面的順序進(jìn)行類搜索:

    • 將以java.*開頭的類委派給父類加載器加載。
    • 否則,將委派列表名單內(nèi)(比如sun或者javax這類核心類的包加入白名單)的類委派給父類加載器加載。
    • 否則,將Import列表中的類委派給Export這個(gè)類的Bundle的類加載器加載。
    • 否則,查找當(dāng)前Bundle的ClassPath,使用自己的類加載器加載。
    • 否則,查找類是否在自己的Fragment Bundle(OSGI框架緩存包)中,如果在,則委派給Fragment Bundle的類加載器加載。
    • 否則,查找Dynamic Import列表的Bundle,委派給對(duì)應(yīng)Bundle的類加載器加載。
    • 否則,類查找失敗。

    這一系列的類加載操作,其實(shí)跟我們上節(jié)實(shí)現(xiàn)的自定義類加載技術(shù)本質(zhì)上是一樣的,只不過實(shí)現(xiàn)OSGI規(guī)范的框架需要提供模塊之間的注冊(cè)通信組件,還有模塊的生命周期管理,版本管理。

    OSGI也只是JVM上面運(yùn)行的一個(gè)普通應(yīng)用實(shí)例,只不過通過模塊內(nèi)聚,版本管理,服務(wù)依賴一系列的管理,實(shí)現(xiàn)了模塊的即時(shí)更新,實(shí)現(xiàn)了熱部署。

    其他熱部署解決方案多數(shù)也是利用類加載器的特點(diǎn)做文章,當(dāng)然不止是類加載器,還會(huì)應(yīng)用字節(jié)碼技術(shù),下面我們主要簡(jiǎn)單列舉應(yīng)用類加載器實(shí)現(xiàn)的熱部署解決方案。

    Groovy

    Groovy兼顧動(dòng)態(tài)腳本語言的功能,使用的時(shí)候無外乎也是通過GroovyClassLoader來加載腳本文件,轉(zhuǎn)為JVM的類對(duì)象。那么每次更新groovy腳本就可以動(dòng)態(tài)更新應(yīng)用,也就達(dá)到了熱部署的功能了。

    Class groovyClass = classLoader.parseClass(new GroovyCodeSource(sourceFile)); GroovyObject instance = (GroovyObject)groovyClass.newInstance();//proxy

    Clojure

    JSP

    JSP其實(shí)翻譯為Servlet后也是由對(duì)應(yīng)新的類加載器去加載,這跟我們上節(jié)講的流程一模一樣,所以這里就補(bǔ)展開講解了。

    介紹完熱部署技術(shù),可能很多同學(xué)對(duì)熱部署的需求已經(jīng)沒有那么強(qiáng)烈,畢竟熱部署過程中帶來的弊端也不容忽視。

    比如替換舊的類加載器過程會(huì)產(chǎn)生大量的內(nèi)存碎片,導(dǎo)致JVM進(jìn)行高負(fù)荷的GC工作,反復(fù)進(jìn)行熱部署還會(huì)導(dǎo)致JVM內(nèi)存不足而導(dǎo)致內(nèi)存溢出,有時(shí)候甚至還不如直接重啟應(yīng)用來得更快一點(diǎn),而且隨著分布式架構(gòu)的演進(jìn)和微服務(wù)的流行,應(yīng)用重啟也早就實(shí)現(xiàn)服務(wù)編排化,配合豐富的部署策略,也可以同樣保證系統(tǒng)穩(wěn)定持續(xù)服務(wù),我們更多的是通過熱部署技術(shù)來深刻認(rèn)識(shí)到JVM加載類的技術(shù)演進(jìn)。

    4.3.2類隔離

    背景

    先介紹一下類隔離的背景,我們費(fèi)了那么大的勁設(shè)計(jì)出類加載器,如果只是用于加載外部類字節(jié)流那就過于浪費(fèi)了。通常我們的應(yīng)用依賴不同的第三方類庫經(jīng)常會(huì)出現(xiàn)不同版本的類庫,如果只是使用系統(tǒng)內(nèi)置的類加載器的話,那么一個(gè)類庫只能加載唯一的一個(gè)版本,想加載其他版本的時(shí)候會(huì)從緩存里面發(fā)現(xiàn)已經(jīng)存在而停止加載。

    但是我們的不同業(yè)務(wù)以來的往往是不同版本的類庫,這時(shí)候就會(huì)出現(xiàn)ClassNotFoundException。為什么只有運(yùn)行的是才會(huì)出現(xiàn)這個(gè)異常呢,因?yàn)榫幾g的時(shí)候我們通常會(huì)使用MAVEN等編譯工具把沖突的版本排除掉。另外一種情況是WEB容器的內(nèi)核依賴的第三方類庫需要跟應(yīng)用依賴的第三方類庫隔離開來,避免一些安全隱患,不然如果共用的話,應(yīng)用升級(jí)依賴版本就會(huì)導(dǎo)致WEB容器不穩(wěn)定。

    基于以上的介紹我們知道類隔離實(shí)在是剛需,那么接下來介紹一下如何實(shí)現(xiàn)這個(gè)剛需。

    原理

    首先我們要了解一下原理,其實(shí)原理很簡(jiǎn)單,真的很簡(jiǎn)單,請(qǐng)?jiān)试S我總結(jié)為“唯一標(biāo)識(shí)原理”。我們知道內(nèi)存里面定位類實(shí)例的坐標(biāo)<類加載器,類全限定名>。那么由這兩個(gè)因子組合起來我們可以得出一種普遍的應(yīng)用,用不同類加載器來加載類相同類(類全限定名一致,版本不一致)是可以實(shí)現(xiàn)的,也就是在JVM看來,有相同類全名的類是完全不同的兩個(gè)實(shí)例,但是在業(yè)務(wù)視角我們卻可以視為相同的類。

    實(shí)現(xiàn)

    原理很簡(jiǎn)單,比如我們知道Spring容器本質(zhì)就是一個(gè)生產(chǎn)和管理bean的集合對(duì)象,但是卻包含了大量的優(yōu)秀設(shè)計(jì)模式和復(fù)雜的框架實(shí)現(xiàn)。同理隔離容器雖然原理很簡(jiǎn)單,但是要實(shí)現(xiàn)一個(gè)高性能可擴(kuò)展的高可用隔離容器,卻不是那么簡(jiǎn)單。我們上文談的場(chǎng)景是在內(nèi)存運(yùn)行的時(shí)候才發(fā)現(xiàn)問題,介紹內(nèi)存隔離技術(shù)之前,我們先普及更為通用的沖突解決方法。

    沖突排除

    沖突總是先發(fā)生在編譯時(shí)期,那么基本Maven工具可以幫我們完成大部分的工作,Maven的工作模式就是將我們第三方類庫的所有依賴都依次檢索,最終排除掉產(chǎn)生沖突的jar包版本。

    沖突適配

    當(dāng)我們無法通過簡(jiǎn)單的排除來解決的時(shí)候,另外一個(gè)方法就是重新裝配第三方類庫,這里我們要介紹一個(gè)開源工具jarjar (https://github.com/shevek/jarjar)。該工具包可以通過字節(jié)碼技術(shù)將我們依賴的第三方類庫重命名,同時(shí)修改代碼里面對(duì)第三方類庫引用的路徑。這樣如果出現(xiàn)同名第三方類庫的話,通過該“硬編碼”的方式修改其中一個(gè)類庫,從而消除了沖突。

    沖突隔離

    上面兩種方式在小型系統(tǒng)比較適合,也比較敏捷高效。但是對(duì)于分布式大型系統(tǒng)的話,通過硬編碼方式來解決沖突就難以完成了。辦法就是通過隔離容器,從邏輯上區(qū)分類庫的作用域,從而對(duì)內(nèi)存的類進(jìn)行隔離。

    5.內(nèi)存管理

    5.1內(nèi)存結(jié)構(gòu)

    5.1.1邏輯分區(qū)

    JVM內(nèi)存從應(yīng)用邏輯上可分為如下區(qū)域。

    • 程序計(jì)數(shù)器:字節(jié)碼行號(hào)指示器,每個(gè)線程需要一個(gè)程序計(jì)數(shù)器
    • 虛擬機(jī)棧:方法執(zhí)行時(shí)創(chuàng)建棧幀(存儲(chǔ)局部變量,操作棧,動(dòng)態(tài)鏈接,方法出口)編譯時(shí)期就能確定占用空間大小,線程請(qǐng)求的棧深度超過jvm運(yùn)行深度時(shí)拋StackOverflowError,當(dāng)jvm棧無法申請(qǐng)到空閑內(nèi)存時(shí)拋OutOfMemoryError,通過-Xss,-Xsx來配置初始內(nèi)存
    • 本地方法棧:執(zhí)行本地方法,如操作系統(tǒng)native接口
    • 堆:存放對(duì)象的空間,通過-Xmx,-Xms配置堆大小,當(dāng)堆無法申請(qǐng)到內(nèi)存時(shí)拋OutOfMemoryError
    • 方法區(qū):存儲(chǔ)類數(shù)據(jù),常量,常量池,靜態(tài)變量,通過MaxPermSize參數(shù)配置
    • 對(duì)象訪問:初始化一個(gè)對(duì)象,其引用存放于棧幀,對(duì)象存放于堆內(nèi)存,對(duì)象包含屬性信息和該對(duì)象父類、接口等類型數(shù)據(jù)(該類型數(shù)據(jù)存儲(chǔ)在方法區(qū)空間,對(duì)象擁有類型數(shù)據(jù)的地址)

    而實(shí)際上JVM內(nèi)存分類實(shí)際上的物理分區(qū)還有更為詳細(xì),整體上分為堆內(nèi)存和非堆內(nèi)存,具體介紹如下。

    5.1.2 內(nèi)存模型

    堆內(nèi)存

    堆內(nèi)存是運(yùn)行時(shí)的數(shù)據(jù)區(qū),從中分配所有java類實(shí)例和數(shù)組的內(nèi)存,可以理解為目標(biāo)應(yīng)用依賴的對(duì)象。堆在JVM啟動(dòng)時(shí)創(chuàng)建,并且在應(yīng)用程序運(yùn)行時(shí)可能會(huì)增大或減小。可以使用-Xms 選項(xiàng)指定堆的大小。堆可以是固定大小或可變大小,具體取決于垃圾收集策略。可以使用-Xmx選項(xiàng)設(shè)置最大堆大小。默認(rèn)情況下,最大堆大小設(shè)置為64 MB。

    JVM堆內(nèi)存在物理上分為兩部分:新生代和老年代。新生代是為分配新對(duì)象而保留堆空間。當(dāng)新生代占用完時(shí),Minor GC垃圾收集器會(huì)對(duì)新生代區(qū)域執(zhí)行垃圾回收動(dòng)作,其中在新生代中生活了足夠長(zhǎng)的所有對(duì)象被遷移到老年代,從而釋放新生代空間以進(jìn)行更多的對(duì)象分配。此垃圾收集稱為 Minor GC。新生代分為三個(gè)子區(qū)域:伊甸園Eden區(qū)和兩個(gè)幸存區(qū)S0和S1。

    關(guān)于新生代內(nèi)存空間:

    • 大多數(shù)新創(chuàng)建的對(duì)象都位于Eden區(qū)內(nèi)存空間
    • 當(dāng)Eden區(qū)填滿對(duì)象時(shí),執(zhí)行Minor GC并將所有幸存對(duì)象移動(dòng)到其中一個(gè)幸存區(qū)空間
    • Minor GC還會(huì)檢查幸存區(qū)對(duì)象并將其移動(dòng)到其他幸存者空間,也即是幸存區(qū)總有一個(gè)是空的
    • 在多次GC后還存活的對(duì)象被移動(dòng)到老年代內(nèi)存空間。至于經(jīng)過多少次GC晉升老年代則由參數(shù)配置,通常為15

    當(dāng)老年區(qū)填滿時(shí),老年區(qū)同樣會(huì)執(zhí)行垃圾回收,老年區(qū)還包含那些經(jīng)過多Minor GC后還存活的長(zhǎng)壽對(duì)象。垃圾收集器在老年代內(nèi)存中執(zhí)行的回收稱為Major GC,通常需要更長(zhǎng)的時(shí)間。

    非堆內(nèi)存

    JVM的堆以外內(nèi)存稱為非堆內(nèi)存。也即是JVM自身預(yù)留的內(nèi)存區(qū)域,包含JVM緩存空間,類結(jié)構(gòu)如常量池、字段和方法數(shù)據(jù),方法,構(gòu)造方法。類非堆內(nèi)存的默認(rèn)最大大小為64 MB。可以使用-XX:MaxPermSize VM選項(xiàng)更改此選項(xiàng),非堆內(nèi)存通常包含如下性質(zhì)的區(qū)域空間:

    元空間(Metaspace)

    在Java 8以上版本已經(jīng)沒有Perm Gen這塊區(qū)域了,這也意味著不會(huì)再由關(guān)于“java.lang.OutOfMemoryError:PermGen”內(nèi)存問題存在了。與駐留在Java堆中的Perm Gen不同,Metaspace不是堆的一部分。類元數(shù)據(jù)多數(shù)情況下都是從本地內(nèi)存中分配的。

    默認(rèn)情況下,元空間會(huì)自動(dòng)增加其大小(直接又底層操作系統(tǒng)提供),而Perm Gen始終具有固定的上限。可以使用兩個(gè)新標(biāo)志來設(shè)置Metaspace的大小,它們是:“ - XX:MetaspaceSize ”和“ -XX:MaxMetaspaceSize ”。Metaspace背后的含義是類的生命周期及其元數(shù)據(jù)與類加載器的生命周期相匹配。

    也就是說,只要類加載器處于活動(dòng)狀態(tài),元數(shù)據(jù)就會(huì)在元數(shù)據(jù)空間中保持活動(dòng)狀態(tài),并且無法釋放。

    代碼緩存

    運(yùn)行Java程序時(shí),它以分層方式執(zhí)行代碼。在第一層,它使用客戶端編譯器(C1編譯器)來編譯代碼。分析數(shù)據(jù)用于服務(wù)器編譯的第二層(C2編譯器),以優(yōu)化的方式編譯該代碼。

    默認(rèn)情況下,Java 7中未啟用分層編譯,但在Java 8中啟用了分層編譯。實(shí)時(shí)(JIT)編譯器將編譯的代碼存儲(chǔ)在稱為代碼緩存的區(qū)域中。它是一個(gè)保存已編譯代碼的特殊堆。如果該區(qū)域的大小超過閾值,則該區(qū)域?qū)⒈凰⑿?#xff0c;并且GC不會(huì)重新定位這些對(duì)象。

    Java 8中已經(jīng)解決了一些性能問題和編譯器未重新啟用的問題,并且在Java 7中避免這些問題的解決方案之一是將代碼緩存的大小增加到一個(gè)永遠(yuǎn)不會(huì)達(dá)到的程度。

    方法區(qū)

    方法區(qū)域是Perm Gen中空間的一部分,用于存儲(chǔ)類結(jié)構(gòu)(運(yùn)行時(shí)常量和靜態(tài)變量)以及方法和構(gòu)造函數(shù)的代碼。

    內(nèi)存池

    內(nèi)存池由JVM內(nèi)存管理器創(chuàng)建,用于創(chuàng)建不可變對(duì)象池。內(nèi)存池可以屬于Heap或Perm Gen,具體取決于JVM內(nèi)存管理器實(shí)現(xiàn)。

    常量池

    常量包含類運(yùn)行時(shí)常量和靜態(tài)方法,常量池是方法區(qū)域的一部分。

    Java堆棧內(nèi)存

    Java堆棧內(nèi)存用于執(zhí)行線程。它們包含特定于方法的特定值,以及對(duì)從該方法引用的堆中其他對(duì)象的引用。

    Java堆內(nèi)存配置項(xiàng)

    Java提供了許多內(nèi)存配置項(xiàng),我們可以使用它們來設(shè)置內(nèi)存大小及其比例,常用的如下:

    5.2垃圾回收

    5.2.1垃圾回收策略

    流程

    垃圾收集是釋放堆中的空間以分配新對(duì)象的過程。垃圾收集器是JVM管理的進(jìn)程,它可以查看內(nèi)存中的所有對(duì)象,并找出程序任何部分未引用的對(duì)象,刪除并回收空間以分配給其他對(duì)象。通常會(huì)經(jīng)過如下步驟:

    • 標(biāo)記:標(biāo)記哪些對(duì)象被使用,哪些已經(jīng)是無法觸達(dá)的無用對(duì)象
    • 刪除:刪除無用對(duì)象并回收要分配給其他對(duì)象
    • 壓縮:性能考慮,在刪除無用的對(duì)象后,會(huì)將所有幸存對(duì)象集中移動(dòng)到一起,騰出整段空間

    策略

    虛擬機(jī)棧、本地棧和程序計(jì)數(shù)器在編譯完畢后已經(jīng)可以確定所需內(nèi)存空間,程序執(zhí)行完畢后也會(huì)自動(dòng)釋放所有內(nèi)存空間,所以不需要進(jìn)行動(dòng)態(tài)回收優(yōu)化。

    JVM內(nèi)存調(diào)優(yōu)主要針對(duì)堆和方法區(qū)兩大區(qū)域的內(nèi)存。通常對(duì)象分為Strong、sfot、weak和phantom四種類型,強(qiáng)引用不會(huì)被回收,軟引用在內(nèi)存達(dá)到溢出邊界時(shí)回收,弱引用在每次回收周期時(shí)回收,虛引用專門被標(biāo)記為回收對(duì)象,具體回收策略如下:

    對(duì)象優(yōu)先在Eden區(qū)分配:

    • 新生對(duì)象回收策略Minor GC(頻繁)
    • 老年代對(duì)象回收策略Full GC/Major GC(慢)
    • 大對(duì)象直接進(jìn)入老年代:超過3m的對(duì)象直接進(jìn)入老年區(qū) -XX:PretenureSizeThreshold=3145728(3M)
    • 長(zhǎng)期存貨對(duì)象進(jìn)入老年區(qū):Survivor區(qū)中的對(duì)象經(jīng)歷一次Minor GC年齡增加一歲,超過15歲進(jìn)入老年區(qū)-XX:MaxTenuringThreshold=15
    • 動(dòng)態(tài)對(duì)象年齡判定:設(shè)置Survivor區(qū)對(duì)象占用一半空間以上的對(duì)象進(jìn)入老年區(qū)

    算法

    垃圾收集有如下常用的算法:

    • 標(biāo)記-清除
    • 復(fù)制
    • 標(biāo)記-整理
    • 分代收集(新生用復(fù)制,老年用標(biāo)記-整理)

    5.2.2 垃圾回收器

    分類

    • serial收集器:單線程,主要用于client模式
    • ParNew收集器:多線程版的serial,主要用于server模式
    • Parallel Scavenge收集器:線程可控吞吐量(用戶代碼時(shí)間/用戶代碼時(shí)間+垃圾收集時(shí)間),自動(dòng)調(diào)節(jié)吞吐量,用戶新生代內(nèi)存區(qū)
    • Serial Old收集器:老年版本serial
    • Parallel Old收集器:老年版本Parallel Scavenge
    • CMS(Concurrent Mark Sweep)收集器:停頓時(shí)間短,并發(fā)收集
    • G1收集器:分塊標(biāo)記整理,不產(chǎn)生碎片

    配置

    • 串行GC(-XX:+ UseSerialGC):串行GC使用簡(jiǎn)單的標(biāo)記-掃描-整理方法,用于新生代和老年代的垃圾收集,即Minor和Major GC
    • 并行GC(-XX:+ UseParallelGC):并行GC與串行GC相同,不同之處在于它為新生代垃圾收集生成N個(gè)線程,其中N是系統(tǒng)中的CPU核心數(shù)。我們可以使用-XX:ParallelGCThreads = n JVM選項(xiàng)來控制線程數(shù)
    • 并行舊GC(-XX:+ UseParallelOldGC):這與Parallel GC相同,只是它為新生代和老年代垃圾收集使用多個(gè)線程
    • 并發(fā)標(biāo)記掃描(CMS)收集器(-XX:+ UseConcMarkSweepGC):CMS也稱為并發(fā)低暫停收集器。它為老年代做垃圾收集。CMS收集器嘗試通過在應(yīng)用程序線程內(nèi)同時(shí)執(zhí)行大多數(shù)垃圾收集工作來最小化由于垃圾收集而導(dǎo)致的暫停。年輕一代的CMS收集器使用與并行收集器相同的算法。我們可以使用-XX限制CMS收集器中的線程數(shù) :ParallelCMSThreads = n
    • G1垃圾收集器(-XX:+ UseG1GC):G1從長(zhǎng)遠(yuǎn)看要是替換CMS收集器。G1收集器是并行,并發(fā)和遞增緊湊的低暫停垃圾收集器。G1收集器不像其他收集器那樣工作,并且沒有年輕和老一代空間的概念。它將堆空間劃分為多個(gè)大小相等的堆區(qū)域。當(dāng)調(diào)用垃圾收集器時(shí),它首先收集具有較少實(shí)時(shí)數(shù)據(jù)的區(qū)域,因此稱為“Garbage First”也即是G1

    6.執(zhí)行引擎

    6.1執(zhí)行流程

    類加載器加載的類文件字節(jié)碼數(shù)據(jù)流由基于JVM指令集架構(gòu)的執(zhí)行引擎來執(zhí)行。執(zhí)行引擎以指令為單位讀取Java字節(jié)碼。我們知道匯編執(zhí)行的流程是CPU執(zhí)行每一行的匯編指令,同樣JVM執(zhí)行引擎就像CPU一個(gè)接一個(gè)地執(zhí)行機(jī)器命令。字節(jié)碼的每個(gè)命令都包含一個(gè)1字節(jié)的OpCode和附加的操作數(shù)。

    執(zhí)行引擎獲取一個(gè)OpCode并使用操作數(shù)執(zhí)行任務(wù),然后執(zhí)行下一個(gè)OpCode。但Java是用人們可以理解的語言編寫的,而不是用機(jī)器直接執(zhí)行的語言編寫的。因此執(zhí)行引擎必須將字節(jié)碼更改為JVM中的機(jī)器可以執(zhí)行的語言。字節(jié)碼可以通過以下兩種方式之一轉(zhuǎn)化為合適的語言。

    • 解釋器:逐個(gè)讀取,解釋和執(zhí)行字節(jié)碼指令。當(dāng)它逐個(gè)解釋和執(zhí)行指令時(shí),它可以快速解釋一個(gè)字節(jié)碼,但是同時(shí)也只能相對(duì)緩慢的地執(zhí)行解釋結(jié)果,這是解釋語言的缺點(diǎn)。
    • JIT(實(shí)時(shí))編譯器:引入了JIT編譯器來彌補(bǔ)解釋器的缺點(diǎn)。執(zhí)行引擎首先作為解釋器運(yùn)行,并在適當(dāng)?shù)臅r(shí)候,JIT編譯器編譯整個(gè)字節(jié)碼以將其更改為本機(jī)代碼。之后,執(zhí)行引擎不再解釋該方法,而是直接使用本機(jī)代碼執(zhí)行。本地代碼中的執(zhí)行比逐個(gè)解釋指令要快得多。由于本機(jī)代碼存儲(chǔ)在高速緩存中,因此可以快速執(zhí)行編譯的代碼。

    但是,JIT編譯器編譯代碼需要花費(fèi)更多的時(shí)間,而不是解釋器逐個(gè)解釋代碼。因此,如果代碼只執(zhí)行一次,最好是選擇解釋而不是編譯。因此,使用JIT編譯器的JVM在內(nèi)部檢查方法執(zhí)行的頻率,并僅在頻率高于某個(gè)級(jí)別時(shí)編譯方法。

    JVM規(guī)范中未定義執(zhí)行引擎的運(yùn)行方式。因此,JVM廠商使用各種技術(shù)改進(jìn)其執(zhí)行引擎,并引入各種類型的JIT編譯器。 大多數(shù)JIT編譯器運(yùn)行如下圖所示:

    JIT編譯器將字節(jié)碼轉(zhuǎn)換為中間級(jí)表達(dá)式IR,以執(zhí)行優(yōu)化,然后將表達(dá)式轉(zhuǎn)換為本機(jī)代碼。Oracle Hotspot VM使用名為Hotspot Compiler的JIT編譯器。它被稱為Hotspot,因?yàn)镠otspot Compiler通過分析搜索需要以最高優(yōu)先級(jí)進(jìn)行編譯的“Hotspot”,然后將熱點(diǎn)編譯為本機(jī)代碼。

    如果不再頻繁調(diào)用編譯了字節(jié)碼的方法,換句話說,如果該方法不再是熱點(diǎn),則Hotspot VM將從緩存中刪除本機(jī)代碼并以解釋器模式運(yùn)行。Hotspot VM分為服務(wù)器VM和客戶端VM,兩個(gè)VM使用不同的JIT編譯器。

    大多數(shù)Java性能改進(jìn)都是通過改進(jìn)執(zhí)行引擎來實(shí)現(xiàn)的。除了JIT編譯器之外,還引入了各種優(yōu)化技術(shù),因此可以不斷改進(jìn)JVM性能。初始JVM和最新JVM之間的最大區(qū)別是執(zhí)行引擎。

    下面我們通過下圖可以看出JAVA執(zhí)行的流程。

    6.2棧幀結(jié)構(gòu)

    每個(gè)方法調(diào)用開始到執(zhí)行完成的過程,對(duì)應(yīng)這一個(gè)棧幀在虛擬機(jī)棧里面從入棧到出棧的過程。

    • 棧幀包含:局部變量表,操作數(shù)棧,動(dòng)態(tài)連接,方法返回
    • 方法調(diào)用:方法調(diào)用不等于方法執(zhí)行,而且確定調(diào)用方法的版本。
    • 方法調(diào)用字節(jié)碼指令:invokestatic,invokespecial,invokevirtual,invokeinterface
    • 靜態(tài)分派:靜態(tài)類型,實(shí)際類型,編譯器重載時(shí)通過參數(shù)的靜態(tài)類型來確定方法的版本。(選方法)
    • 動(dòng)態(tài)分派:invokevirtual指令把類方法符號(hào)引用解析到不同直接引用上,來確定棧頂?shù)膶?shí)際對(duì)象(選對(duì)象)
    • 單分派:靜態(tài)多分派,相同指令有多個(gè)方法版本。
    • 多分派:動(dòng)態(tài)單分派,方法接受者只能確定唯一一個(gè)。

    下圖是JVM實(shí)例執(zhí)行方法是的內(nèi)存布局。

    6.3早期編譯

    • javac編譯器:解析與符號(hào)表填充,注解處理,生成字節(jié)碼
    • java語法糖:語法糖有助于代碼開發(fā),但是編譯后就會(huì)解開糖衣,還原到基礎(chǔ)語法的class二進(jìn)制文件

    重載要求方法具備不同的特征簽名(不包括返回值),但是class文件中,只要描述不是完全一致的方法就可以共存。

    6.4晚期編譯

    HotSpot虛擬機(jī)內(nèi)的即時(shí)編譯

    • 解析模式 -Xint
    • 編譯模式 -Xcomp
    • 混合模式 Mixed mode
    • 分層編譯:解釋執(zhí)行 -> C1(Client Compiler)編譯 -> C2編譯(Server Compiler)
    • 觸發(fā)條件:基于采樣的熱點(diǎn)探測(cè),基于計(jì)數(shù)器的熱點(diǎn)探測(cè)

    7.性能調(diào)優(yōu)

    7.1調(diào)優(yōu)原則

    我們知道調(diào)優(yōu)的前提是,程序沒有達(dá)到我們的預(yù)期要求,那么第一步要做的是衡量我們的預(yù)期。程序不可能十全十美,我們要做的是通過各種指標(biāo)來衡量系統(tǒng)的性能,最終整體達(dá)到我們的要求。

    7.1.1 環(huán)境

    首先我們要了解系統(tǒng)的運(yùn)行環(huán)境,包括操作系統(tǒng)層面的差異,JVM版本,位數(shù),乃至于硬件的時(shí)鐘周期,總線設(shè)計(jì)甚至機(jī)房溫度,都可能是我們需要考慮的前置條件。

    7.1.2 度量

    首先我們要先給出系統(tǒng)的預(yù)期指標(biāo),在特定的硬件/軟件的配置,然后給出目標(biāo)指標(biāo),比如系統(tǒng)整體輸出接口的QPS,RT,或者更進(jìn)一層,IO讀寫,cpu的load指標(biāo),內(nèi)存的使用率,GC情況都是我們需要預(yù)先考察的對(duì)象。

    7.1.3 監(jiān)測(cè)

    確定了環(huán)境前置條件,分析了度量指標(biāo),第三步是通過工具來監(jiān)測(cè)指標(biāo),下一節(jié)提供了常用JVM調(diào)優(yōu)工具,可以通過不同工具的組合來發(fā)現(xiàn)定位問題,結(jié)合JVM的工作機(jī)制已經(jīng)操作系統(tǒng)層面的調(diào)度流程,按圖索驥來發(fā)現(xiàn)問題,找出問題后才能進(jìn)行優(yōu)化。

    7.1.4 原則

    總體的調(diào)優(yōu)原則如下圖

    圖片來源《Java Performance》

    7.2 調(diào)優(yōu)參數(shù)

    上節(jié)給出了JVM性能調(diào)優(yōu)的原則,我們理清思路后應(yīng)用不同的JVM工具來發(fā)現(xiàn)系統(tǒng)存在的問題,下面列舉的是常用的JVM參數(shù),通過這些參數(shù)指標(biāo)可以更快的幫助我們定位出問題所在。

    7.2.1內(nèi)存查詢

    最常見的與性能相關(guān)的做法之一是根據(jù)應(yīng)用程序要求初始化堆內(nèi)存。這就是我們應(yīng)該指定最小和最大堆大小的原因。以下參數(shù)可用于實(shí)現(xiàn)它:

    -Xms<heap size>[unit] -Xmx<heap size>[unit]

    unit表示要初始化內(nèi)存(由堆大小表示)的單元。單位可以標(biāo)記為GB的“g”,MB的“m”和KB的“k”。例如JVM分配最小2 GB和最大5 GB:

    -Xms2G -Xmx5G

    從Java 8開始Metaspace的大小未被定義,一旦達(dá)到限制JVM會(huì)自動(dòng)增加它,為了避免不必要的不穩(wěn)定性,我們可以設(shè)置Metaspace大小:

    -XX:MaxMetaspaceSize=<metaspace size>[unit]

    默認(rèn)情況下YG的最小大小為1310 MB,最大大小不受限制,我們可以明確地指定它們:

    7.2.2垃圾回收

    JVM有四種類型的GC實(shí)現(xiàn):

    • 串行垃圾收集器
    • 并行垃圾收集器
    • CMS垃圾收集器
    • G1垃圾收集器

    可以使用以下參數(shù)聲明這些實(shí)現(xiàn):

    7.2.3GC記錄

    要嚴(yán)格監(jiān)視應(yīng)用程序運(yùn)行狀況,我們應(yīng)始終檢查JVM的垃圾收集性能,使用以下參數(shù),我們可以記錄GC活動(dòng):

    UseGCLogFileRotation指定日志文件滾動(dòng)的政策,就像log4j的,s4lj等 NumberOfGCLogFiles表示單個(gè)應(yīng)用程序記錄生命周期日志文件的最大數(shù)量。GCLogFileSize指定文件的最大大小。 loggc表示其位置。這里要注意的是,還有兩個(gè)可用的JVM參數(shù)(-XX:+ PrintGCTimeStamps和-XX:+ PrintGCDateStamps),可用于在GC日志中打印日期時(shí)間戳。

    7.2.4內(nèi)存溢出

    大型應(yīng)用程序面臨內(nèi)存不足的錯(cuò)誤是很常見的,這是一個(gè)非常關(guān)鍵的場(chǎng)景,很難復(fù)制以解決問題。

    這就是JVM帶有一些參數(shù)的原因,這些參數(shù)將堆內(nèi)存轉(zhuǎn)儲(chǔ)到一個(gè)物理文件中,以后可以用它來查找泄漏:

    這里有幾點(diǎn)需要注意:

    • 在OutOfMemoryError的情況下, HeapDumpOnOutOfMemoryError指示JVM將堆轉(zhuǎn)儲(chǔ)到物理文件中
    • HeapDumpPath表示要寫入文件的路徑; 任何文件名都可以給出; 但是如果JVM在名稱中找到 標(biāo)記,則導(dǎo)致內(nèi)存不足錯(cuò)誤的進(jìn)程ID將以 .hprof格式附加到文件名
    • OnOutOfMemoryError用于發(fā)出緊急命令,以便在出現(xiàn)內(nèi)存不足錯(cuò)誤時(shí)執(zhí)行; 應(yīng)該在cmd args的空間中使用正確的命令。例如,如果我們想在內(nèi)存不足時(shí)重新啟動(dòng)服務(wù)器,我們可以設(shè)置參數(shù):
    -XX:OnOutOfMemoryError="shutdown -r"
    • UseGCOverheadLimit是一種策略,用于限制在拋出 OutOfMemory錯(cuò)誤之前在GC中花費(fèi)的VM時(shí)間的比例

    7.2.5其他配置

    • -server:啟用“Server Hotspot VM”; 默認(rèn)情況下,此參數(shù)在64位JVM中使用
    • -XX:+ UseStringDeduplication: Java 8引入了這個(gè)JVM參數(shù),通過創(chuàng)建相同 String的太多實(shí)例來減少不必要的內(nèi)存使用 ; 這通過將重復(fù)的 String值減少到單個(gè)全局char []數(shù)組來優(yōu)化堆內(nèi)存
    • -XX:+ UseLWPSynchronization:設(shè)置基于 LWP(輕量級(jí)進(jìn)程)的同步策略而不是基于線程的同步
    • -XX:LargePageSizeInBytes:設(shè)置用于Java堆的大頁面大小; 它采用GB / MB / KB的參數(shù); 通過更大的頁面大小,我們可以更好地利用虛擬內(nèi)存硬件資源; 但是這可能會(huì)導(dǎo)致 PermGen的空間大小增加,從而可以強(qiáng)制減小Java堆空間的大小
    • -XX:MaxHeapFreeRatio:設(shè)置 GC后堆的最大自由百分比,以避免收縮
    • -XX:MinHeapFreeRatio:設(shè)置 GC后堆的最小自由百分比以避免擴(kuò)展,監(jiān)視堆使用情況
    • -XX:SurvivorRatio:Eden區(qū) /幸存者空間大小的比例
    • -XX:+ UseLargePages:如果系統(tǒng)支持,則使用大頁面內(nèi)存; 如果使用此JVM參數(shù),OpenJDK 7往往會(huì)崩潰
    • -XX:+ UseStringCache:啟用字符串池中可用的常用分配字符串的緩存
    • -XX:+ UseCompressedStrings:對(duì) String對(duì)象使用 byte []類型,可以用純ASCII格式表示
    • -XX:+ OptimizeStringConcat:它盡可能優(yōu)化字符串連接操作

    7.3 調(diào)優(yōu)工具

    7.3.1命令行工具

    虛擬機(jī)進(jìn)程狀況工具:jps -lvm


    診斷命令工具:jcmd

    用來發(fā)送診斷命令請(qǐng)求到JVM,這些請(qǐng)求是控制Java的運(yùn)行記錄,它必須在運(yùn)行JVM的同一臺(tái)機(jī)器上使用,并且具有用于啟動(dòng)JVM的相同有效用戶和分組,可以使用以下命令創(chuàng)建堆轉(zhuǎn)儲(chǔ)(hprof轉(zhuǎn)儲(chǔ)):

    jcmd GC.heap_dump filename =

    虛擬機(jī)統(tǒng)計(jì)信息監(jiān)視工具:jstat

    提供有關(guān)運(yùn)行的應(yīng)用程序的性能和資源消耗的信息。在診斷性能問題時(shí),可以使用該工具,特別是與堆大小調(diào)整和垃圾回收相關(guān)的問題。jstat不需要虛擬機(jī)啟動(dòng)任何特殊配置。

    jstat -gc pid interval count

    java配置信息工具:jinfo

    jinfo -flag pid

    java內(nèi)存映像工具:jmap

    用于生成堆轉(zhuǎn)儲(chǔ)文件

    jmap -dump:format=b,file=java.bin pid

    虛擬機(jī)堆轉(zhuǎn)儲(chǔ)快照分析工具:jhat

    jhat file 分析堆轉(zhuǎn)儲(chǔ)文件,通過瀏覽器訪問分析文件


    java堆棧跟蹤工具:jstack

    用于生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照threaddump或者Javacore

    jstack [ option ] vmid

    堆和CPU分析工具:HPROF

    HPROF是每個(gè)JDK版本附帶的堆和CPU分析工具。它是一個(gè)動(dòng)態(tài)鏈接庫(DLL),它使用Java虛擬機(jī)工具接口(JVMTI)與JVM連接。該工具將分析信息以ASCII或二進(jìn)制格式寫入文件或套接字。HPROF工具能夠顯示CPU使用情況,堆分配統(tǒng)計(jì)信息和監(jiān)視爭(zhēng)用配置文件。

    此外,它還可以報(bào)告JVM中所有監(jiān)視器和線程的完整堆轉(zhuǎn)儲(chǔ)和狀態(tài)。在診斷問題方面,HPROF在分析性能,鎖爭(zhēng)用,內(nèi)存泄漏和其他問題時(shí)非常有用。

    java -agentlib:hprof = heap = sites target.class

    7.3.2可視化工具

    • jconsole
    • jvisualvm

    8.字節(jié)增強(qiáng)

    我們從類加載的應(yīng)用介紹了熱部署和類隔離兩大應(yīng)用場(chǎng)景,但是基于類加載器的技術(shù)始終只是獨(dú)立于JVM內(nèi)核功能而存在的,也就是所有實(shí)現(xiàn)都只是基于最基礎(chǔ)的類加載機(jī)制,并無應(yīng)用其他JVM 高級(jí)特性,本章節(jié)我們開始從字節(jié)增強(qiáng)的層面介紹JVM的一些高級(jí)特性。

    說到字節(jié)增強(qiáng)我們最先想到的是字節(jié)碼,也就是本文最開頭所要研究的class文件,任何合法的源碼編譯成class后被類加載器加載進(jìn)JVM的方法區(qū),也就是以字節(jié)碼的形態(tài)存活在JVM的內(nèi)存空間。這也就是我們?yōu)槭裁船F(xiàn)有講明白類的結(jié)構(gòu)和加載過程,而字節(jié)碼增強(qiáng)技術(shù)不只是在內(nèi)存里面對(duì)class的字節(jié)碼進(jìn)行操縱,更為復(fù)雜的是class聯(lián)動(dòng)的上下游對(duì)象生命周期的管理。

    首先我們回憶一下我們開發(fā)過程中最為熟悉的一個(gè)場(chǎng)景就是本地debug調(diào)試代碼。可能很多同學(xué)都已經(jīng)習(xí)慣在IDE上對(duì)某句代碼打上斷點(diǎn),然后逐步往下追蹤代碼執(zhí)行的步驟。

    我們進(jìn)一步想想,這個(gè)是怎么實(shí)現(xiàn)的,是一股什么樣的力量能把已經(jīng)跑起來的線程踩下剎車,一步一步往前挪?我們知道線程運(yùn)行其實(shí)就是在JVM的棧空間上不斷的把代碼對(duì)應(yīng)的JVM指令集不斷的送到CPU執(zhí)行。

    那能阻止這個(gè)流程的力量也肯定是發(fā)生在JVM范圍內(nèi),所以我們可以很輕松的預(yù)測(cè)到這肯定是JVM提供的機(jī)制,而不是IDE真的有這樣的能力,只不過是JVM把這種能力封裝成接口暴露出去,然后提供給IDE調(diào)用,而IDE只不過是通過界面交互來調(diào)用這些接口而已。那么下面我們就來介紹JVM這種重要的能力。

    8.1JPDA

    上面所講的JVM提供的程序運(yùn)行斷點(diǎn)能力,其實(shí)JVM提供的一個(gè)工具箱JVMTI(JVM TOOL Interface)提供的接口,而這個(gè)工具箱是一套叫做JPDA的架構(gòu)定義的,本節(jié)我們就來聊聊JPDA。

    JPDA(Java Platform Debugger Architecture)Java平臺(tái)調(diào)試架構(gòu),既不是一個(gè)應(yīng)用程序,也不是調(diào)試工具,而是定義了一系列設(shè)計(jì)良好的接口和協(xié)議用于調(diào)試java代碼,我們將會(huì)從三個(gè)層面來講解JPDA。

    8.1.1概念

    JVMTI

    JVMTI(Java Virtual Machine Tool Interface)Java 虛擬機(jī)調(diào)試接口,處于最底層,是我們上文所提到的JVM開放的能力,JPDA規(guī)定了JDK必須提供一個(gè)叫做JVMTI(Java6之前是由JVMPI和JVMDI組成,Java6開始廢棄掉統(tǒng)一為JVMTI)的工具箱,也就是定義了一系列接口能力,比如獲取棧幀、設(shè)置斷點(diǎn)、斷點(diǎn)響應(yīng)等接口,具體開放的能力參考JVMDI官方API文檔。

    JDWP

    JDWP(Java Debug Wire Protocol)Java 調(diào)試連線協(xié)議,存在在中間層,定義信息格式,定義調(diào)試者和被調(diào)試程序之間請(qǐng)求的協(xié)議轉(zhuǎn)換,位于JDI下一層,JDI更為抽象,JDWP則關(guān)注實(shí)現(xiàn)。也就是說JVM定義好提供的能力,但是如何調(diào)用JVM提供的接口也是需要規(guī)范的,就比如我們Servlet容器也接收正確合法的HTTP請(qǐng)求就可以成功調(diào)用接口。

    JPDA同樣也規(guī)范了調(diào)用JVMTI接口需要傳入數(shù)據(jù)的規(guī)范,也就是請(qǐng)求包的格式,類別HTTP的數(shù)據(jù)包格式。但是JPDA并不關(guān)心請(qǐng)求來源,也就是說只要調(diào)用JVMTI的請(qǐng)求方式和數(shù)據(jù)格式對(duì)了就可以,不論是來做遠(yuǎn)程調(diào)用還是本地調(diào)用。

    JDWP制定了調(diào)試者和被調(diào)試應(yīng)用的字節(jié)流動(dòng)機(jī)制,但沒有限定具體實(shí)現(xiàn),可以是遠(yuǎn)程的socket連接,或者本機(jī)的共享內(nèi)存,當(dāng)然還有自定義實(shí)現(xiàn)的通信協(xié)議。既然只是規(guī)范了調(diào)用協(xié)議,并不局限請(qǐng)求來源,而且也沒限制語言限制,所以非java語言只要發(fā)起調(diào)用符合規(guī)范就可以,這個(gè)大大豐富了異構(gòu)應(yīng)用場(chǎng)景,具體的協(xié)議細(xì)節(jié)可以參考JDWP官方規(guī)范文檔。

    JDI

    JDI(Java Debug Interface)Java調(diào)試接口處在最上層,基于Java開發(fā)的調(diào)試接口,也就是我們調(diào)試客戶端,客戶端代碼封裝在jdk下面tools.jar的com.sun.jdi包里面,java程序可以直接調(diào)用的接口集合,具體提供的功能可以參考JDI官方API文檔。

    8.1.2原理

    介紹完JPDA的架構(gòu)體系后,我們了解到JAVA調(diào)試平臺(tái)各個(gè)層級(jí)的作用,這一節(jié)我們更近一步講解JPDA各個(gè)層面的工作原理,以及三個(gè)層級(jí)結(jié)合起來時(shí)如何交互的。

    JVMTI

    我們JVMTI是JVM提供的一套本地接口,包含了非常豐富的功能,我們調(diào)試和優(yōu)化代碼需要操作JVM,多數(shù)情況下就是調(diào)用到JVMTI,從官網(wǎng)我們可以看到,JVMTI包含了對(duì)JVM線程/內(nèi)存/堆/棧/類/方法/變量/事件/定時(shí)器處理等的20多項(xiàng)功能。

    但其實(shí)我們通常不是直接調(diào)用JVMTI,而是創(chuàng)建一個(gè)代理客戶端,我們可以自由的定義對(duì)JVMTI的操作然后打包到代理客戶端里面如libagent.so。當(dāng)目標(biāo)程序執(zhí)行時(shí)會(huì)啟動(dòng)JVM,這個(gè)時(shí)候在目標(biāo)程序運(yùn)行前會(huì)加載代理客戶端,所以代理客戶端是跟目標(biāo)程序運(yùn)行在同一個(gè)進(jìn)程上。

    這樣一來外部請(qǐng)求就通過代理客戶端間接調(diào)用到JVMTI,這樣的好處是我們可以在客戶端Agent里面定制高級(jí)功能,而且代理客戶端編譯打包成一個(gè)動(dòng)態(tài)鏈接庫之后可以復(fù)用,提高效率。我們簡(jiǎn)單描述一下代理客戶端Agent的工作流程。

    建立代理客戶端首先需要定義Agent的入口函數(shù),猶如Java類的main方法一樣:

    JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);

    然后JVM在啟動(dòng)的時(shí)候就會(huì)把JVMTI的指針JavaVM傳給代理的入口函數(shù),options則是傳參,有了這個(gè)指針后代理就可以充分調(diào)用JVMTI的函數(shù)了。

    //設(shè)置斷點(diǎn),參數(shù)是調(diào)試目標(biāo)方法和行數(shù)位置 jvmtiError SetBreakpoint(jvmtiEnv* env,jmethodID method,jlocation location); //當(dāng)目標(biāo)程序執(zhí)行到指定斷點(diǎn),目標(biāo)線程則被掛起 jvmtiError SuspendThread(jvmtiEnv* env,jthread thread);

    當(dāng)然除了JVM啟動(dòng)時(shí)可以加載代理,運(yùn)行過程中也是可以的,這個(gè)下文我們講字節(jié)碼增強(qiáng)還會(huì)再說到。

    JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char *options, void *reserved);

    有興趣的同學(xué)可以自己動(dòng)手寫一個(gè)Agent試試,通過調(diào)用JVMTI接口可以實(shí)現(xiàn)自己定制化的調(diào)試工具。

    JDWP

    上文我們知道調(diào)用JVMTI需要建立一個(gè)代理客戶端,但是假如我建立了包含通用功能的Agent想開發(fā)出去給所有調(diào)試器使用,有一種方式是資深開發(fā)者通過閱讀我的文檔后進(jìn)行開發(fā)調(diào)用,還有另外一種方式就是我在我的Agent里面加入了JDWP協(xié)議模塊,這樣調(diào)試器就可以不用關(guān)心我的接口細(xì)節(jié),只需按照閱讀的協(xié)議發(fā)起請(qǐng)求即可。JDWP是調(diào)試器和JVM中間的協(xié)議規(guī)范,類似HTTP協(xié)議一樣,JDWP也定義規(guī)范了握手協(xié)議和報(bào)文格式。

    調(diào)試器發(fā)起請(qǐng)求的握手流程:

    • 調(diào)試器發(fā)送一段包含“JDWP-Handshake”的14個(gè)bytes的字符串
    • JVM回復(fù)同樣的內(nèi)容“JDWP-Handshake”

    完成握手流程后就可以像HTTP一樣向JVM的代理客戶端發(fā)送請(qǐng)求數(shù)據(jù),同時(shí)回復(fù)所需參數(shù)。請(qǐng)求和回復(fù)的數(shù)據(jù)幀也有嚴(yán)格的結(jié)構(gòu),請(qǐng)求的數(shù)據(jù)格式為Command Packet,回復(fù)的格式為Reply Packet,包含包頭和數(shù)據(jù)兩部分,具體格式參考官網(wǎng)。

    實(shí)際上JDWP卻是也是通過建立代理客戶端來實(shí)現(xiàn)報(bào)文格式的規(guī)范,也就是JDWP Agent 里面的JDWPTI實(shí)現(xiàn)了JDWP對(duì)協(xié)議的定義。JDWP的功能是由JDWP傳輸接口(Java Debug Wire Protocol Transport Interface)實(shí)現(xiàn)的,具體流程其實(shí)跟JVMTI差不多,也是講JDWPTI編譯打包成代理庫后,在JVM啟動(dòng)的時(shí)候加載到目標(biāo)進(jìn)程。

    那么調(diào)試器調(diào)用的過程就是JDWP Agent接收到請(qǐng)求后,調(diào)用JVMTI Agent,JDWP負(fù)責(zé)定義好報(bào)文數(shù)據(jù),而JDWPTI則是具體的執(zhí)行命令和響應(yīng)事件。

    JDI

    前面已經(jīng)解釋了JVMTI和JDWP的工作原理和交互機(jī)制,剩下的就是搞清楚面向用戶的JDI是如何運(yùn)行的。首先JDI位于JPDA的最頂層入口,它的實(shí)現(xiàn)是通過JAVA語言編寫的,所以可以理解為Java調(diào)試客戶端對(duì)JDI接口的封裝調(diào)用,比如我們熟悉的IDE界面啟動(dòng)調(diào)試,或者JAVA的命令行調(diào)試客戶端JDB。

    通常我們?cè)O(shè)置好目標(biāo)程序的斷點(diǎn)之后啟動(dòng)程序,然后通過調(diào)試器啟動(dòng)程序之前,調(diào)試器會(huì)先獲取JVM管理器,然后通過JVM管理器對(duì)象virtualMachineManager獲取連接器Connector,調(diào)試器與虛擬機(jī)獲得鏈接后就可以啟動(dòng)目標(biāo)程序了。如下代碼:

    VirtualMachineManager virtualMachineManager = Bootstrap.virtualMachineManager();

    JDI完成調(diào)試需要實(shí)現(xiàn)的功能有三個(gè)模塊:數(shù)據(jù)、鏈接、事件

    數(shù)據(jù)

    調(diào)試器要調(diào)試的程序在目標(biāo)JVM上,那么調(diào)試之前肯定需要將目標(biāo)程序的執(zhí)行環(huán)境同步過來,不然我們壓根就不知道要調(diào)試什么,所以需要一種鏡像機(jī)制,把目標(biāo)程序的堆棧方法區(qū)包含的數(shù)據(jù)以及接收到的事件請(qǐng)求都映射到調(diào)試器上面。那么JDI的底層接口Mirror就是干這樣的事,具體數(shù)據(jù)結(jié)構(gòu)可以查詢文檔。

    鏈接

    我們知道調(diào)試器跟目標(biāo)JVM直接的通訊是雙向的,所以鏈接雙方都可以發(fā)起。一個(gè)調(diào)試器可以鏈接多個(gè)目標(biāo)JVM,但是一個(gè)目標(biāo)虛擬機(jī)只能提供給一個(gè)調(diào)試器,不然就亂套了不知道聽誰指令了。JDI定義三種鏈接器:啟動(dòng)鏈接器(LaunchingConnector)、依附鏈接器(AttachingConnector)、監(jiān)聽鏈接器(ListeningConnector)和。分別對(duì)應(yīng)的場(chǎng)景是目標(biāo)程序JVM啟動(dòng)時(shí)發(fā)起鏈接、調(diào)試器中途請(qǐng)求接入目標(biāo)程序JVM和調(diào)試器監(jiān)聽到被調(diào)試程序返回請(qǐng)求時(shí)發(fā)起的鏈接。

    事件

    也就是調(diào)試過程中對(duì)目標(biāo)JVM返回請(qǐng)求的響應(yīng)。

    講解完JPDA體系的實(shí)現(xiàn)原理,我們?cè)俅问崂硪幌抡{(diào)試的整個(gè)流程:

    調(diào)試器 —> JDI客戶端 —> JDWP Agent—> JVMTI Agent —>> JVMTI —> Application

    8.1.3 實(shí)現(xiàn)

    現(xiàn)在我們已經(jīng)對(duì)整個(gè)JPDA結(jié)構(gòu)有了深入理解,接下來我們就通過對(duì)這些樸素的原理來實(shí)現(xiàn)程序的斷點(diǎn)調(diào)試。當(dāng)然我們不會(huì)在這里介紹從IDE的UI斷點(diǎn)調(diào)試的過程,因?yàn)閷?duì)這套是使用已經(jīng)非常熟悉了,我們知道IDE的UI斷點(diǎn)調(diào)試本質(zhì)上是調(diào)試器客戶端對(duì)JDI的調(diào)用,那我們就通過一個(gè)調(diào)試的案例來解釋一下這背后的原理。

    搭建服務(wù)

    首先我們需要先搭建一個(gè)可供調(diào)試的web服務(wù),這里我首選springboot+來搭建,通過官網(wǎng)生成樣例project或者maven插件都可以,具體的太基礎(chǔ)的就不在這里演示,該服務(wù)只提供一個(gè)Controller包含的一個(gè)簡(jiǎn)單方法。如果使用Tomcat部署,則可以通過自有的開關(guān)catalina jpda start來啟動(dòng)debug模式。

    package com.zooncool.debug.rest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController("/debug") public class DebugController {@GetMappingpublic String ask(@RequestParam("name") String name) {String message = "are you ok?" + name;return message;} }

    啟動(dòng)服務(wù)

    搭建好服務(wù)之后我們先啟動(dòng)服務(wù),我們通過maven來啟動(dòng)服務(wù),其中涉及到的一些參數(shù)下面解釋。

    mvn spring-boot:run -Drun.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001"

    或者

    mvn spring-boot:run -Drun.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8001"
    • mvn:maven的腳本命令這個(gè)不用解釋
    • Spring-boot:run:啟動(dòng)springboot工程
    • -Drun.jvmArguments:執(zhí)行jvm環(huán)境的參數(shù),里面的參數(shù)值才是關(guān)鍵
    • -Xdebug
    Xdebug開啟調(diào)試模式,為非標(biāo)準(zhǔn)參數(shù),也就是可能在其他JVM上面是不可用的,Java5之后提供了標(biāo)準(zhǔn)的執(zhí)行參數(shù)agentlib,下面兩種參數(shù)同樣可以開啟debug模式,但是在JIT方面有所差異,這里先不展開。java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8001 java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8001
    • Xrunjdwp/jdwp=transport:表示連接模式是本地內(nèi)存共享還是遠(yuǎn)程socket連接
    • server:y表示打開socket監(jiān)聽調(diào)試器的請(qǐng)求;n表示被調(diào)試程序像客戶端一樣主動(dòng)連接調(diào)試器
    • suspend:y表示被調(diào)試程序需要等到調(diào)試器的連接請(qǐng)求之后才能啟動(dòng)運(yùn)行,在此之前都是掛起的,n表示被調(diào)試程序無需等待直接運(yùn)行。
    • address:被調(diào)試程序啟動(dòng)debug模式后監(jiān)聽請(qǐng)求的地址和端口,地址缺省為本地。

    執(zhí)行完上述命令后,就等著我們調(diào)試器的請(qǐng)求接入到目標(biāo)程序了。

    調(diào)試接入

    我們知道java的調(diào)試器客戶端為jdb,下面我們就使用jdb來接入我們的目標(biāo)程序。

    #jdb 通過attach參數(shù)選擇本地目標(biāo)程序,同時(shí)附上目標(biāo)程序的源碼,回想之前我們講到的JDI的鏡像接口,就是把目標(biāo)程序的堆棧結(jié)構(gòu)同步過來,如果能我們提供的源碼對(duì)應(yīng)上,那就可以在源碼上面顯示斷點(diǎn)標(biāo)志 $ jdb -attach localhost:8001 -sourcepath /Users/linzhenhua/Documents/repositories/practice/stackify-master/remote-debugging/src/main/java/ 設(shè)置未捕獲的java.lang.Throwable 設(shè)置延遲的未捕獲的java.lang.Throwable 正在初始化jdb...#stop,選擇對(duì)應(yīng)方法設(shè)置斷點(diǎn) > stop in com.zooncool.debug.rest.DebugController.ask(java.lang.String) 設(shè)置斷點(diǎn)com.zooncool.debug.rest.DebugController.ask(java.lang.String)#如果我們?cè)O(shè)置不存在的方法為斷點(diǎn),則會(huì)有錯(cuò)誤提示 > stop in com.zooncool.debug.rest.DebugController.ask2(java.lang.String) 無法設(shè)置斷點(diǎn)com.zooncool.debug.rest.DebugController.ask2(java.lang.String): com.zooncool.debug.rest.DebugController中沒有方法ask2#這時(shí)候我們已經(jīng)設(shè)置完斷點(diǎn),就可以發(fā)起個(gè)HTTP請(qǐng)求 #http://localhost:7001/remote-debugging/debug/ask?name=Jack #發(fā)起請(qǐng)求后我們回到j(luò)db控制臺(tái),觀察是否命中斷點(diǎn) > 斷點(diǎn)命中: "線程=http-nio-7001-exec-5", com.zooncool.debug.rest.DebugController.ask(), 行=14 bci=0 14 String message = "are you ok?" + name;#list,對(duì)照源碼,確實(shí)是進(jìn)入ask方法第一行命中斷點(diǎn),也就是14行,這時(shí)候我們可以查看源碼 http-nio-7001-exec-5[1] list 10 @RestController("/debug") 11 public class DebugController { 12 @GetMapping 13 public String ask(@RequestParam("name") String name) { 14 => String message = "are you ok?" + name; 15 return message; 16 } 17 }#locals,觀察完源碼,我們想獲取name的傳參,跟URL傳入的一致 http-nio-7001-exec-5[1] locals 方法參數(shù): name = "Jack" 本地變量:#print name,打印入?yún)?http-nio-7001-exec-5[1] print namename = "Jack"#where,查詢方法調(diào)用的棧幀,從web容器入口調(diào)用方法到目標(biāo)方法的調(diào)用鏈路 http-nio-7001-exec-5[1] where[1] com.zooncool.debug.rest.DebugController.ask (DebugController.java:14)...[55] java.lang.Thread.run (Thread.java:748) #step,下一步到下一行代碼 http-nio-7001-exec-5[1] step > 已完成的步驟: "線程=http-nio-7001-exec-5", com.zooncool.debug.rest.DebugController.ask(), 行=15 bci=20 15 return message;#step up,完成當(dāng)前方法的調(diào)用 http-nio-7001-exec-5[1] step up > 已完成的步驟: "線程=http-nio-7001-exec-5", sun.reflect.NativeMethodAccessorImpl.invoke(), 行=62 bci=103#cont,結(jié)束調(diào)試,執(zhí)行完畢 http-nio-7001-exec-5[1] cont > #clear,完成調(diào)試任務(wù),清除斷點(diǎn) > clear 斷點(diǎn)集:斷點(diǎn)com.zooncool.debug.rest.DebugController.ask(java.lang.String)斷點(diǎn)com.zooncool.debug.rest.DebugController.ask2(java.lang.String) #選擇一個(gè)斷點(diǎn)刪除 > clear com.zooncool.debug.rest.DebugController.ask(java.lang.String) 已刪除: 斷點(diǎn)com.zooncool.debug.rest.DebugController.ask(java.lang.String)

    我們已經(jīng)完成了命令行調(diào)試的全部流程,stop/list/locals/print name/where/step/step up/cont/clear這些命令其實(shí)就是IDE的UI后臺(tái)調(diào)用的腳本。而這些腳本就是基于JDI層面的接口所提供的能力,下面我們還有重點(diǎn)觀察一個(gè)核心功能,先從頭再設(shè)置一下斷點(diǎn)。

    #stop,選擇對(duì)應(yīng)方法設(shè)置斷點(diǎn) > stop in com.zooncool.debug.rest.DebugController.ask(java.lang.String) 設(shè)置斷點(diǎn)com.zooncool.debug.rest.DebugController.ask(java.lang.String) #這時(shí)候我們已經(jīng)設(shè)置完斷點(diǎn),就可以發(fā)起個(gè)HTTP請(qǐng)求 #http://localhost:7001/remote-debugging/debug/ask?name=Jack #發(fā)起請(qǐng)求后我們回到j(luò)db控制臺(tái),觀察是否命中斷點(diǎn) > 斷點(diǎn)命中: "線程=http-nio-7001-exec-5", com.zooncool.debug.rest.DebugController.ask(), 行=14 bci=0 14 String message = "are you ok?" + name; #print name,打印入?yún)?http-nio-7001-exec-5[1] print namename = "Jack" #如果這個(gè)時(shí)候我們想替換掉Jack,換成Lucy http-nio-7001-exec-6[1] set name = "Lucy" name = "Lucy" = "Lucy" #進(jìn)入下一步 http-nio-7001-exec-6[1] step > 已完成的步驟: "線程=http-nio-7001-exec-6", com.zooncool.debug.rest.DebugController.ask(), 行=15 bci=20 15 return message; #查看變量,我們發(fā)現(xiàn)name的值已經(jīng)被修改了 http-nio-7001-exec-6[1] locals 方法參數(shù): name = "Lucy" 本地變量: message = "are you ok?Lucy"

    至此我們已經(jīng)完成了JPDA的原理解析到調(diào)試實(shí)踐,也理解了JAVA調(diào)試的工作機(jī)制,其中留下一個(gè)重要的彩蛋就是通過JPDA進(jìn)入調(diào)試模式,我們可以動(dòng)態(tài)的修改JVM內(nèi)存對(duì)象和類的內(nèi)容,這也講引出下文我們要介紹的字節(jié)碼增強(qiáng)技術(shù)。

    8.2 熱替換

    8.2.1概念

    終于來到熱替換這節(jié)了,前文我們做了好多鋪墊,介紹熱替換之前我們稍稍回顧一下熱部署。我們知道熱部署是“獨(dú)立”于JVM之外的一門對(duì)類加載器應(yīng)用的技術(shù),通常是應(yīng)用容器借助自定義類加載器的迭代,無需重啟JVM缺能更新代碼從而達(dá)到熱部署,也就是說熱部署是JVM之外容器提供的一種能力。

    而本節(jié)我們介紹的熱替換技術(shù)是實(shí)打?qū)岼VM提供的能力,是JVM提供的一種能夠?qū)崟r(shí)更新內(nèi)存類結(jié)構(gòu)的一種能力,這種實(shí)時(shí)更新JVM方法區(qū)類結(jié)構(gòu)的能力當(dāng)然也是無需重啟JVM實(shí)例。

    熱替換HotSwap是Sun公司在Java 1.4版本引入的一種新實(shí)驗(yàn)性技術(shù),也就是上一節(jié)我們介紹JPDA提到的調(diào)試模式下可以動(dòng)態(tài)替換類結(jié)構(gòu)的彩蛋,這個(gè)功能被集成到JPDA框架的接口集合里面,首先我們定義好熱替換的概念。

    熱替換(HotSwap):使用字節(jié)碼增強(qiáng)技術(shù)替換JVM內(nèi)存里面類的結(jié)構(gòu),包括對(duì)應(yīng)類的對(duì)象,而不需要重啟虛擬機(jī)。

    8.2.2原理

    前文從宏觀上介紹了JVM實(shí)例的內(nèi)存布局和垃圾回收機(jī)制,微觀上也解釋了類的結(jié)構(gòu)和類加載機(jī)制,上一節(jié)又學(xué)習(xí)了JAVA的調(diào)試框架,基本上我們對(duì)JVM的核心模塊都已經(jīng)摸透了,剩下的就是攻克字節(jié)碼增強(qiáng)的技術(shù)了。

    而之前講的字節(jié)碼增強(qiáng)技術(shù)也僅僅是放在JPDA里面作為實(shí)驗(yàn)性技術(shù),而且僅僅局限在方法體和變量的修改,無法動(dòng)態(tài)修改方法簽名或者增刪方法,因?yàn)樽止?jié)碼增強(qiáng)涉及到垃圾回收機(jī)制,類結(jié)構(gòu)變更,對(duì)象引用,即時(shí)編譯等復(fù)雜問題。在HotSwap被引進(jìn)后至今,JCP也未能通過正式的字節(jié)碼增強(qiáng)實(shí)現(xiàn)。

    JAVA是一門靜態(tài)語言,而字節(jié)碼增強(qiáng)所要達(dá)的效果就是讓Java像動(dòng)態(tài)語言一樣跑起來,無需重啟服務(wù)器。下面我們介紹字節(jié)碼增強(qiáng)的基本原理。

    反射代理

    反射代理不能直接修改內(nèi)存方法區(qū)的字節(jié)碼,但是可以抽象出一層代理,通過內(nèi)存新增實(shí)例來實(shí)現(xiàn)類的更新

    原生接口

    jdk上層提供面向java語言的字節(jié)碼增強(qiáng)接口java.lang.instrument,通過實(shí)現(xiàn)ClassFileTransformer接口來操作JVM方法區(qū)的類文件字節(jié)碼。

    JVMTI代理

    JVM的JVMTI接口包含了操作方法區(qū)類文件字節(jié)碼的函數(shù),通過創(chuàng)建代理,將JVMTI的指針JavaVM傳給代理,從而擁有JVM 本地操作字節(jié)碼的方法引用。

    類加載器織入

    字節(jié)碼增強(qiáng)接口加上類加載器的織入,結(jié)合起來也是一種熱替換技術(shù)。

    JVM增強(qiáng)

    直接新增JVM分支,增加字節(jié)碼增強(qiáng)功能。

    8.2.3實(shí)現(xiàn)

    但是盡管字節(jié)碼增強(qiáng)是一門復(fù)雜的技術(shù),這并不妨礙我們進(jìn)一步的探索,下面我們介紹幾種常見的實(shí)現(xiàn)方案。

    • Instrumentation
    • AspectJ
    • ASM
    • DCEVM
    • JREBEL
    • CGLIB
    • javassist
    • BCEL

    具體的我會(huì)挑兩個(gè)具有代表性的工具深入講解,篇幅所限,這里就補(bǔ)展開了。

    9.總結(jié)

    JVM是程序發(fā)展至今的一顆隗寶,是程序設(shè)計(jì)和工程實(shí)現(xiàn)的完美結(jié)合。JVM作為作為三大工業(yè)級(jí)程序語言為首JAVA的根基,本文試圖在瀚如煙海的JVM海洋中找出其中最耀眼的冰山,并力求用簡(jiǎn)潔的邏輯線索把各個(gè)冰山串起來,在腦海中對(duì)JVM的觀感有更加立體的認(rèn)識(shí)。

    更近一步的認(rèn)識(shí)JVM對(duì)程序設(shè)計(jì)的功力提示大有裨益,而本文也只是將海平面上的冰山鏈接起來,但這只是冰山一角,JVM更多的底層設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié)還遠(yuǎn)遠(yuǎn)沒有涉及到,而且也不乏知識(shí)盲區(qū)而沒有提及到的,路漫漫其修遠(yuǎn)兮,JVM本身也在不斷的推陳出新,借此機(jī)會(huì)總結(jié)出JVM的核心體系,以此回顧對(duì)JVM知識(shí)的查漏補(bǔ)缺,也是一次JVM的認(rèn)知升級(jí)。

    最后還是例牌來兩張圖結(jié)束JVM的介紹,希望對(duì)更的同學(xué)有幫助。

    總結(jié)

    以上是生活随笔為你收集整理的java并发核心知识体系精讲_JVM核心知识体系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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

    亚洲人成网站色7799 | 国产在线精品一区二区三区直播 | 人妻天天爽夜夜爽一区二区 | 精品久久综合1区2区3区激情 | 国产精品无码mv在线观看 | 久久久亚洲欧洲日产国码αv | 国产内射爽爽大片视频社区在线 | 国产亚洲精品久久久久久大师 | 色偷偷人人澡人人爽人人模 | 欧美 日韩 人妻 高清 中文 | 久久这里只有精品视频9 | 国产av人人夜夜澡人人爽麻豆 | 六十路熟妇乱子伦 | 最近免费中文字幕中文高清百度 | 国产免费无码一区二区视频 | aⅴ亚洲 日韩 色 图网站 播放 | 日本一区二区更新不卡 | 午夜时刻免费入口 | 一个人看的www免费视频在线观看 | 久久亚洲国产成人精品性色 | 国产成人精品一区二区在线小狼 | 中文字幕+乱码+中文字幕一区 | 性色av无码免费一区二区三区 | 妺妺窝人体色www在线小说 | 亚洲aⅴ无码成人网站国产app | 国产成人精品一区二区在线小狼 | 无码精品国产va在线观看dvd | 日本大香伊一区二区三区 | 波多野结衣一区二区三区av免费 | 亚洲性无码av中文字幕 | 亚欧洲精品在线视频免费观看 | 在线а√天堂中文官网 | 国产无套粉嫩白浆在线 | 亚洲精品国产第一综合99久久 | 无码人妻丰满熟妇区毛片18 | 国产综合色产在线精品 | 激情内射亚州一区二区三区爱妻 | 久久综合给合久久狠狠狠97色 | 曰本女人与公拘交酡免费视频 | 狠狠cao日日穞夜夜穞av | 综合激情五月综合激情五月激情1 | 色综合天天综合狠狠爱 | 帮老师解开蕾丝奶罩吸乳网站 | 亚洲成a人一区二区三区 | 亚洲天堂2017无码 | 男女爱爱好爽视频免费看 | 亚洲日韩一区二区 | 精品乱码久久久久久久 | 999久久久国产精品消防器材 | 国产av无码专区亚洲awww | 激情国产av做激情国产爱 | 国产精品久免费的黄网站 | 又大又黄又粗又爽的免费视频 | 国产无套内射久久久国产 | 在线欧美精品一区二区三区 | 亚洲精品一区二区三区四区五区 | 精品人人妻人人澡人人爽人人 | 精品久久8x国产免费观看 | 一本久久伊人热热精品中文字幕 | 精品无码成人片一区二区98 | 丰满护士巨好爽好大乳 | 蜜桃无码一区二区三区 | 沈阳熟女露脸对白视频 | 亚洲а∨天堂久久精品2021 | 午夜精品久久久内射近拍高清 | 国产成人精品久久亚洲高清不卡 | 亚洲日韩精品欧美一区二区 | 成人无码精品一区二区三区 | 婷婷五月综合激情中文字幕 | 精品日本一区二区三区在线观看 | 亚洲阿v天堂在线 | 日韩精品久久久肉伦网站 | 999久久久国产精品消防器材 | 午夜福利试看120秒体验区 | 亚洲国产精品久久久天堂 | 久久精品99久久香蕉国产色戒 | 久久综合九色综合97网 | 精品乱子伦一区二区三区 | 欧美真人作爱免费视频 | 丰满人妻一区二区三区免费视频 | 亚洲精品一区三区三区在线观看 | 内射欧美老妇wbb | 国产精品无套呻吟在线 | 国产黑色丝袜在线播放 | 久久久成人毛片无码 | 精品aⅴ一区二区三区 | 国精产品一区二区三区 | 日韩精品乱码av一区二区 | 中文字幕 亚洲精品 第1页 | 国产一区二区不卡老阿姨 | 成人无码视频在线观看网站 | 色婷婷综合中文久久一本 | 天天躁日日躁狠狠躁免费麻豆 | 免费无码的av片在线观看 | 亚洲精品国产a久久久久久 | 国产乱人偷精品人妻a片 | aa片在线观看视频在线播放 | 67194成是人免费无码 | 亚洲熟悉妇女xxx妇女av | 国产熟妇另类久久久久 | 亚洲小说图区综合在线 | 荡女精品导航 | 午夜精品久久久内射近拍高清 | 国产性生交xxxxx无码 | 欧美三级a做爰在线观看 | 欧美三级a做爰在线观看 | 亚洲欧美日韩国产精品一区二区 | 精品一区二区三区无码免费视频 | 中文无码成人免费视频在线观看 | 国产精品沙发午睡系列 | 国产麻豆精品一区二区三区v视界 | 欧美zoozzooz性欧美 | 亚洲狠狠色丁香婷婷综合 | 欧美第一黄网免费网站 | 人妻夜夜爽天天爽三区 | 性史性农村dvd毛片 | 无码乱肉视频免费大全合集 | 国语自产偷拍精品视频偷 | 东京无码熟妇人妻av在线网址 | 精品亚洲韩国一区二区三区 | 麻豆国产97在线 | 欧洲 | 狂野欧美性猛交免费视频 | 高清国产亚洲精品自在久久 | 高清不卡一区二区三区 | 亚洲熟熟妇xxxx | 国产综合色产在线精品 | 日韩精品a片一区二区三区妖精 | 国产无av码在线观看 | 久久久久久久久蜜桃 | 国产亚洲人成a在线v网站 | 国产成人综合色在线观看网站 | 青草视频在线播放 | 亚洲欧美日韩国产精品一区二区 | 亚洲 另类 在线 欧美 制服 | 国产97在线 | 亚洲 | 啦啦啦www在线观看免费视频 | 久久亚洲中文字幕精品一区 | 麻花豆传媒剧国产免费mv在线 | 色老头在线一区二区三区 | 亚洲熟妇自偷自拍另类 | 久久精品中文字幕一区 | 日韩人妻无码一区二区三区久久99 | 精品无码av一区二区三区 | 午夜福利不卡在线视频 | 精品久久久久久亚洲精品 | 亚洲中文字幕成人无码 | 国产香蕉尹人视频在线 | 色爱情人网站 | 在线成人www免费观看视频 | 欧洲欧美人成视频在线 | 亚洲一区二区三区无码久久 | 999久久久国产精品消防器材 | 欧洲欧美人成视频在线 | 一本加勒比波多野结衣 | 中文亚洲成a人片在线观看 | 久久久久久久女国产乱让韩 | 亚洲va欧美va天堂v国产综合 | 久久国产自偷自偷免费一区调 | 国内揄拍国内精品少妇国语 | 亚洲精品综合一区二区三区在线 | 亚洲中文字幕av在天堂 | 亚欧洲精品在线视频免费观看 | 久青草影院在线观看国产 | 俺去俺来也www色官网 | 日韩亚洲欧美精品综合 | 久久久av男人的天堂 | 丝袜 中出 制服 人妻 美腿 | 亚洲男人av香蕉爽爽爽爽 | 亚洲成在人网站无码天堂 | 国产成人综合在线女婷五月99播放 | 爽爽影院免费观看 | 国产亚洲精品久久久久久久久动漫 | 99久久久无码国产精品免费 | 亚洲色www成人永久网址 | 亚洲综合无码一区二区三区 | 成人一在线视频日韩国产 | 亚洲自偷自偷在线制服 | 国产三级久久久精品麻豆三级 | 日本丰满护士爆乳xxxx | 日韩av无码中文无码电影 | 久久久国产一区二区三区 | 男女性色大片免费网站 | 黑森林福利视频导航 | 熟妇激情内射com | 黑人粗大猛烈进出高潮视频 | 少妇性l交大片欧洲热妇乱xxx | 国内精品人妻无码久久久影院 | 国产电影无码午夜在线播放 | 99久久精品无码一区二区毛片 | 丰满少妇人妻久久久久久 | www国产精品内射老师 | 巨爆乳无码视频在线观看 | 久久精品国产大片免费观看 | 久久国产36精品色熟妇 | 国产97色在线 | 免 | 亚洲aⅴ无码成人网站国产app | 亚洲国产精品久久久久久 | 成 人 网 站国产免费观看 | 国产艳妇av在线观看果冻传媒 | www国产亚洲精品久久久日本 | 国产美女极度色诱视频www | 狠狠cao日日穞夜夜穞av | 领导边摸边吃奶边做爽在线观看 | 强开小婷嫩苞又嫩又紧视频 | 中文精品无码中文字幕无码专区 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲精品国产a久久久久久 | 欧美性色19p | 国产精品18久久久久久麻辣 | 久久熟妇人妻午夜寂寞影院 | 色婷婷久久一区二区三区麻豆 | 欧美成人高清在线播放 | 人妻与老人中文字幕 | 国产亚洲精品久久久ai换 | 青青青手机频在线观看 | 成人女人看片免费视频放人 | 扒开双腿吃奶呻吟做受视频 | 日韩精品乱码av一区二区 | 亚洲欧美日韩成人高清在线一区 | 国产熟女一区二区三区四区五区 | 精品久久久久香蕉网 | 中文字幕无码日韩欧毛 | 波多野结衣乳巨码无在线观看 | 成 人 网 站国产免费观看 | 高清国产亚洲精品自在久久 | 成年女人永久免费看片 | 国产精品国产三级国产专播 | 日韩在线不卡免费视频一区 | 国产成人无码午夜视频在线观看 | 国产成人无码a区在线观看视频app | 红桃av一区二区三区在线无码av | 欧美老妇交乱视频在线观看 | 国产亚av手机在线观看 | 免费人成网站视频在线观看 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲成a人片在线观看日本 | 国产免费观看黄av片 | 久久久久久久久蜜桃 | 国产黑色丝袜在线播放 | 无码国产乱人伦偷精品视频 | 免费视频欧美无人区码 | 国产口爆吞精在线视频 | 久久久久久久人妻无码中文字幕爆 | 无码帝国www无码专区色综合 | 夜夜高潮次次欢爽av女 | 国产午夜亚洲精品不卡 | 欧美自拍另类欧美综合图片区 | 熟妇人妻激情偷爽文 | 午夜理论片yy44880影院 | 在线观看免费人成视频 | 国产免费久久久久久无码 | 天天躁夜夜躁狠狠是什么心态 | 久久综合久久自在自线精品自 | 在线а√天堂中文官网 | 精品夜夜澡人妻无码av蜜桃 | 国产绳艺sm调教室论坛 | 亚洲男人av香蕉爽爽爽爽 | 国产成人无码a区在线观看视频app | 国产精品-区区久久久狼 | 无码中文字幕色专区 | 性啪啪chinese东北女人 | 亚洲小说图区综合在线 | 久久久精品国产sm最大网站 | 国产无遮挡又黄又爽免费视频 | 欧美日韩一区二区综合 | 正在播放东北夫妻内射 | 三级4级全黄60分钟 | 欧美色就是色 | 精品国产国产综合精品 | 亚洲国产成人av在线观看 | 亚洲欧洲中文日韩av乱码 | 日日碰狠狠躁久久躁蜜桃 | 精品久久久久久亚洲精品 | 亚洲va欧美va天堂v国产综合 | 久久久久人妻一区精品色欧美 | 国产手机在线αⅴ片无码观看 | 国内少妇偷人精品视频免费 | 久久久久亚洲精品中文字幕 | 亚洲欧美精品aaaaaa片 | 少妇愉情理伦片bd | 亚洲乱码日产精品bd | 久久精品无码一区二区三区 | 精品国产一区二区三区四区 | 扒开双腿吃奶呻吟做受视频 | 国产亚洲精品久久久久久国模美 | 久久久久国色av免费观看性色 | 伦伦影院午夜理论片 | 国产欧美精品一区二区三区 | 桃花色综合影院 | 国产又爽又猛又粗的视频a片 | 国产熟妇高潮叫床视频播放 | 无码国产激情在线观看 | 国产99久久精品一区二区 | 欧美一区二区三区 | 免费国产黄网站在线观看 | 人妻体内射精一区二区三四 | 日本成熟视频免费视频 | 成人av无码一区二区三区 | 东京热男人av天堂 | 一本久久伊人热热精品中文字幕 | 98国产精品综合一区二区三区 | 97久久国产亚洲精品超碰热 | 欧美真人作爱免费视频 | 日本免费一区二区三区最新 | 白嫩日本少妇做爰 | 亚洲色欲色欲天天天www | 亚洲成av人综合在线观看 | 小sao货水好多真紧h无码视频 | 一二三四社区在线中文视频 | 国产后入清纯学生妹 | 精品一区二区三区无码免费视频 | 真人与拘做受免费视频一 | 欧美国产亚洲日韩在线二区 | 欧美喷潮久久久xxxxx | 精品国产av色一区二区深夜久久 | 亚洲国产av精品一区二区蜜芽 | 久久97精品久久久久久久不卡 | 高中生自慰www网站 | 国产精品a成v人在线播放 | 蜜桃臀无码内射一区二区三区 | av小次郎收藏 | 日本成熟视频免费视频 | 亚洲欧美日韩国产精品一区二区 | 国产精品美女久久久网av | 又大又紧又粉嫩18p少妇 | 中文字幕乱码中文乱码51精品 | 18无码粉嫩小泬无套在线观看 | 亚洲欧美国产精品专区久久 | 99久久久无码国产精品免费 | 无码国模国产在线观看 | 天堂а√在线中文在线 | 国产激情精品一区二区三区 | 狠狠色噜噜狠狠狠狠7777米奇 | 高清不卡一区二区三区 | 亚洲一区二区三区四区 | 亚洲中文字幕在线无码一区二区 | 2020久久香蕉国产线看观看 | 久久国产精品萌白酱免费 | 国内揄拍国内精品少妇国语 | av无码电影一区二区三区 | 国产精品久免费的黄网站 | 少妇人妻偷人精品无码视频 | 国内精品一区二区三区不卡 | 婷婷丁香五月天综合东京热 | 久久aⅴ免费观看 | 成人三级无码视频在线观看 | 色老头在线一区二区三区 | 日本精品高清一区二区 | 亚洲欧美中文字幕5发布 | 5858s亚洲色大成网站www | 好屌草这里只有精品 | 久久精品国产大片免费观看 | 国产特级毛片aaaaaaa高清 | 久久亚洲中文字幕精品一区 | 日韩亚洲欧美中文高清在线 | 午夜精品一区二区三区的区别 | 欧洲vodafone精品性 | 麻豆蜜桃av蜜臀av色欲av | 欧美35页视频在线观看 | 图片小说视频一区二区 | 欧美人与牲动交xxxx | 亚洲а∨天堂久久精品2021 | 鲁鲁鲁爽爽爽在线视频观看 | 麻豆md0077饥渴少妇 | 少妇久久久久久人妻无码 | 中文字幕 人妻熟女 | 午夜不卡av免费 一本久久a久久精品vr综合 | 夜精品a片一区二区三区无码白浆 | 欧美日韩一区二区三区自拍 | 亚洲国精产品一二二线 | 国产人妖乱国产精品人妖 | 无码成人精品区在线观看 | 97精品人妻一区二区三区香蕉 | 国产亚洲精品精品国产亚洲综合 | 1000部啪啪未满十八勿入下载 | 一本色道婷婷久久欧美 | 成人试看120秒体验区 | 中文字幕无码av波多野吉衣 | 国产精品久久久久久亚洲影视内衣 | 黑人大群体交免费视频 | 性欧美疯狂xxxxbbbb | 久久精品无码一区二区三区 | 理论片87福利理论电影 | 精品国产一区av天美传媒 | 亚洲s色大片在线观看 | 中文字幕精品av一区二区五区 | 国产精品香蕉在线观看 | 图片小说视频一区二区 | 国内揄拍国内精品少妇国语 | 亚洲第一无码av无码专区 | 国产人成高清在线视频99最全资源 | 欧美色就是色 | 天天躁夜夜躁狠狠是什么心态 | 亚洲区小说区激情区图片区 | 色欲av亚洲一区无码少妇 | 荫蒂添的好舒服视频囗交 | 成人无码精品1区2区3区免费看 | 天天综合网天天综合色 | 日本精品人妻无码77777 天堂一区人妻无码 | 国产激情精品一区二区三区 | 性生交大片免费看l | 久久人人97超碰a片精品 | 婷婷五月综合缴情在线视频 | 免费乱码人妻系列无码专区 | 思思久久99热只有频精品66 | 日本免费一区二区三区最新 | 久久久久99精品国产片 | 丰满人妻精品国产99aⅴ | 亚洲一区二区三区 | 亚洲国产高清在线观看视频 | 精品成在人线av无码免费看 | 2019nv天堂香蕉在线观看 | 色五月丁香五月综合五月 | 扒开双腿疯狂进出爽爽爽视频 | 欧美三级a做爰在线观看 | 激情五月综合色婷婷一区二区 | 天天拍夜夜添久久精品 | 国产欧美精品一区二区三区 | 一本色道久久综合狠狠躁 | 亚洲综合另类小说色区 | 捆绑白丝粉色jk震动捧喷白浆 | 亚洲精品综合一区二区三区在线 | 欧美性黑人极品hd | 蜜臀aⅴ国产精品久久久国产老师 | 成在人线av无码免观看麻豆 | 久久综合给久久狠狠97色 | 久久99精品国产麻豆蜜芽 | 国产成人无码午夜视频在线观看 | 亚洲成av人片在线观看无码不卡 | 亚洲a无码综合a国产av中文 | 亚洲高清偷拍一区二区三区 | 午夜无码区在线观看 | 欧美怡红院免费全部视频 | 亚洲无人区一区二区三区 | 国产精品鲁鲁鲁 | 色欲综合久久中文字幕网 | 国产 精品 自在自线 | 97人妻精品一区二区三区 | 在线欧美精品一区二区三区 | 国产精品怡红院永久免费 | 免费看男女做好爽好硬视频 | 久久久久久久人妻无码中文字幕爆 | 国产精品人妻一区二区三区四 | 成人一在线视频日韩国产 | 丰满少妇人妻久久久久久 | 亚洲人成网站在线播放942 | 国产av无码专区亚洲a∨毛片 | 亚洲色大成网站www | 国内精品久久毛片一区二区 | 亚洲熟妇色xxxxx欧美老妇 | 国内老熟妇对白xxxxhd | 精品一二三区久久aaa片 | 久久精品国产一区二区三区肥胖 | 国产又粗又硬又大爽黄老大爷视 | 中文字幕乱码亚洲无线三区 | 成人毛片一区二区 | 亚洲 欧美 激情 小说 另类 | 亚洲午夜无码久久 | 国产亚洲美女精品久久久2020 | 国产av久久久久精东av | 国产精品第一区揄拍无码 | 日本欧美一区二区三区乱码 | 日韩少妇白浆无码系列 | 国产精品久久久久久久9999 | 亚洲精品一区二区三区大桥未久 | 欧美喷潮久久久xxxxx | 久久久精品国产sm最大网站 | 国产九九九九九九九a片 | 国产精品美女久久久久av爽李琼 | 麻豆国产97在线 | 欧洲 | 性开放的女人aaa片 | 亚洲日韩精品欧美一区二区 | 国产女主播喷水视频在线观看 | 99精品国产综合久久久久五月天 | 国产成人精品三级麻豆 | 天堂а√在线地址中文在线 | 丰满人妻精品国产99aⅴ | 中文字幕日产无线码一区 | 国产特级毛片aaaaaa高潮流水 | 久久99精品国产麻豆 | 亚洲日韩av一区二区三区中文 | 国产精品第一区揄拍无码 | 午夜无码人妻av大片色欲 | 天干天干啦夜天干天2017 | 精品熟女少妇av免费观看 | 亚洲综合色区中文字幕 | 在线观看国产午夜福利片 | 国产成人精品一区二区在线小狼 | 中国女人内谢69xxxxxa片 | 亚洲色大成网站www国产 | 日韩人妻无码一区二区三区久久99 | 少妇无码一区二区二三区 | 色综合久久久无码网中文 | 蜜臀av无码人妻精品 | 青青青爽视频在线观看 | 国产性生交xxxxx无码 | 精品亚洲韩国一区二区三区 | 国产国产精品人在线视 | 日韩亚洲欧美中文高清在线 | 精品久久久久香蕉网 | 一本大道伊人av久久综合 | 暴力强奷在线播放无码 | 中文字幕人妻无码一区二区三区 | 波多野结衣aⅴ在线 | 少女韩国电视剧在线观看完整 | 亚洲爆乳大丰满无码专区 | 亚洲 a v无 码免 费 成 人 a v | 欧美熟妇另类久久久久久不卡 | 天堂久久天堂av色综合 | 国产熟妇高潮叫床视频播放 | 国产精品久久久久7777 | 久久精品国产99久久6动漫 | 1000部夫妻午夜免费 | 久久综合激激的五月天 | 一区二区三区乱码在线 | 欧洲 | 欧美真人作爱免费视频 | 人妻少妇被猛烈进入中文字幕 | 国产精品.xx视频.xxtv | 精品一区二区三区波多野结衣 | 131美女爱做视频 | 在线成人www免费观看视频 | 免费无码午夜福利片69 | 久久精品无码一区二区三区 | 无码人妻少妇伦在线电影 | 亚洲性无码av中文字幕 | 一本色道久久综合亚洲精品不卡 | 伦伦影院午夜理论片 | 成 人影片 免费观看 | aⅴ在线视频男人的天堂 | 亚洲国产欧美国产综合一区 | 狠狠综合久久久久综合网 | 国产成人av免费观看 | 天干天干啦夜天干天2017 | 久久午夜夜伦鲁鲁片无码免费 | 动漫av网站免费观看 | 人人超人人超碰超国产 | 国产精品亚洲一区二区三区喷水 | 色欲久久久天天天综合网精品 | 丰满岳乱妇在线观看中字无码 | 成人av无码一区二区三区 | 成在人线av无码免观看麻豆 | 成人无码视频免费播放 | 天堂在线观看www | 亲嘴扒胸摸屁股激烈网站 | 色综合天天综合狠狠爱 | 亚洲中文字幕无码中文字在线 | 免费观看的无遮挡av | 噜噜噜亚洲色成人网站 | 亚洲成色在线综合网站 | 亚洲精品久久久久久久久久久 | 亚洲 欧美 激情 小说 另类 | 秋霞成人午夜鲁丝一区二区三区 | 久久久久亚洲精品男人的天堂 | 亚洲精品国产第一综合99久久 | 国产国语老龄妇女a片 | www国产精品内射老师 | 亚洲色大成网站www | 性生交大片免费看女人按摩摩 | 亚洲精品久久久久avwww潮水 | 亚洲色偷偷偷综合网 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产 精品 自在自线 | 曰韩无码二三区中文字幕 | 97精品人妻一区二区三区香蕉 | 国产色在线 | 国产 | 亚洲国产精品美女久久久久 | 国产精品亚洲а∨无码播放麻豆 | 少妇被粗大的猛进出69影院 | 国产 浪潮av性色四虎 | 午夜肉伦伦影院 | 无码播放一区二区三区 | 日本www一道久久久免费榴莲 | 亚洲成a人片在线观看日本 | 熟妇人妻中文av无码 | 国产精品久久久久久亚洲影视内衣 | 亚洲中文字幕在线无码一区二区 | 国产精品人人爽人人做我的可爱 | 麻豆蜜桃av蜜臀av色欲av | 狂野欧美性猛xxxx乱大交 | 无码精品国产va在线观看dvd | 国产精品a成v人在线播放 | 99久久人妻精品免费二区 | 麻豆国产97在线 | 欧洲 | 日本熟妇浓毛 | 国产精品久久久 | 少妇性l交大片欧洲热妇乱xxx | 蜜臀av无码人妻精品 | 亚洲小说春色综合另类 | 国产精品-区区久久久狼 | 亚洲aⅴ无码成人网站国产app | 成人亚洲精品久久久久 | 丰满人妻被黑人猛烈进入 | 宝宝好涨水快流出来免费视频 | 日韩av激情在线观看 | 国产疯狂伦交大片 | 久久97精品久久久久久久不卡 | 波多野42部无码喷潮在线 | 奇米影视7777久久精品人人爽 | 久久www免费人成人片 | 国产乱子伦视频在线播放 | 国产精品丝袜黑色高跟鞋 | 国产精品嫩草久久久久 | 久热国产vs视频在线观看 | 欧美黑人巨大xxxxx | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 亚洲成色www久久网站 | 久久精品中文字幕大胸 | 夜夜夜高潮夜夜爽夜夜爰爰 | 欧美成人高清在线播放 | 日日干夜夜干 | 色窝窝无码一区二区三区色欲 | √天堂中文官网8在线 | 国产成人av免费观看 | 欧美国产日产一区二区 | 纯爱无遮挡h肉动漫在线播放 | 亚洲综合另类小说色区 | 色婷婷欧美在线播放内射 | 久久久久se色偷偷亚洲精品av | 亚洲狠狠色丁香婷婷综合 | 欧美午夜特黄aaaaaa片 | 久久久久久九九精品久 | 久久久中文字幕日本无吗 | 亚洲欧洲中文日韩av乱码 | 无码免费一区二区三区 | 亚洲中文字幕在线无码一区二区 | 日韩无套无码精品 | 亚洲一区二区三区香蕉 | 中文字幕人成乱码熟女app | 激情人妻另类人妻伦 | 亚洲精品一区二区三区四区五区 | 初尝人妻少妇中文字幕 | 午夜福利试看120秒体验区 | 亚洲区欧美区综合区自拍区 | 日本精品久久久久中文字幕 | 日韩亚洲欧美中文高清在线 | 国产激情无码一区二区app | 亚洲区欧美区综合区自拍区 | 成人免费视频视频在线观看 免费 | 999久久久国产精品消防器材 | 人妻有码中文字幕在线 | 久久久久久av无码免费看大片 | 久久天天躁狠狠躁夜夜免费观看 | 熟女体下毛毛黑森林 | 国内精品人妻无码久久久影院蜜桃 | 永久黄网站色视频免费直播 | a国产一区二区免费入口 | 亚洲精品久久久久久一区二区 | 精品欧美一区二区三区久久久 | 少妇无码吹潮 | 亚洲精品久久久久久一区二区 | 亚洲综合无码久久精品综合 | 亚洲精品久久久久久久久久久 | 夜夜高潮次次欢爽av女 | 动漫av网站免费观看 | 四十如虎的丰满熟妇啪啪 | 国产精品igao视频网 | 日韩视频 中文字幕 视频一区 | 国产在线精品一区二区三区直播 | 精品国产一区二区三区四区在线看 | 日韩人妻无码中文字幕视频 | 性欧美videos高清精品 | 久久99精品国产.久久久久 | 日韩人妻无码中文字幕视频 | 久久精品人人做人人综合试看 | 7777奇米四色成人眼影 | 国产午夜亚洲精品不卡 | 55夜色66夜色国产精品视频 | 欧美国产日韩久久mv | 乱人伦人妻中文字幕无码 | 久久无码专区国产精品s | 岛国片人妻三上悠亚 | 亚洲色欲色欲欲www在线 | 99久久精品日本一区二区免费 | 久久这里只有精品视频9 | 一本久久a久久精品亚洲 | 性欧美牲交在线视频 | 图片区 小说区 区 亚洲五月 | 亚洲国产精品一区二区美利坚 | 久久99热只有频精品8 | 性做久久久久久久免费看 | 国产精品久久久久久久9999 | 久精品国产欧美亚洲色aⅴ大片 | 国产高清不卡无码视频 | 久久久精品国产sm最大网站 | 中文无码成人免费视频在线观看 | 熟妇人妻无乱码中文字幕 | 亚洲阿v天堂在线 | 国产综合在线观看 | 中文字幕无线码 | 人妻尝试又大又粗久久 | 精品国产国产综合精品 | 久久久久国色av免费观看性色 | 久9re热视频这里只有精品 | aa片在线观看视频在线播放 | 欧美三级a做爰在线观看 | 亚洲中文字幕无码一久久区 | 欧美熟妇另类久久久久久多毛 | 久久亚洲中文字幕无码 | 蜜臀aⅴ国产精品久久久国产老师 | 午夜福利一区二区三区在线观看 | 日日碰狠狠躁久久躁蜜桃 | 国产成人综合美国十次 | 欧美怡红院免费全部视频 | 国产精品无码mv在线观看 | 麻豆国产人妻欲求不满谁演的 | 国产特级毛片aaaaaa高潮流水 | 免费网站看v片在线18禁无码 | 色老头在线一区二区三区 | 午夜丰满少妇性开放视频 | 无码中文字幕色专区 | 国产精品亚洲lv粉色 | 国产两女互慰高潮视频在线观看 | 无码帝国www无码专区色综合 | 国产内射老熟女aaaa | 精品无人国产偷自产在线 | 成人性做爰aaa片免费看不忠 | 久青草影院在线观看国产 | 欧美性猛交xxxx富婆 | 国产在线精品一区二区高清不卡 | 奇米影视888欧美在线观看 | 天天av天天av天天透 | 国产精品无码一区二区三区不卡 | 日日摸日日碰夜夜爽av | 99久久精品午夜一区二区 | 国产av无码专区亚洲a∨毛片 | 欧美日韩精品 | 麻豆国产97在线 | 欧洲 | 久久天天躁狠狠躁夜夜免费观看 | 国产69精品久久久久app下载 | 欧美日本免费一区二区三区 | 久久久久免费精品国产 | 中国大陆精品视频xxxx | 久久久久99精品国产片 | 人妻中文无码久热丝袜 | 国产精品美女久久久久av爽李琼 | 无遮挡国产高潮视频免费观看 | av小次郎收藏 | 国产成人无码午夜视频在线观看 | 7777奇米四色成人眼影 | 又粗又大又硬又长又爽 | 国产一区二区三区四区五区加勒比 | 熟妇女人妻丰满少妇中文字幕 | 男女下面进入的视频免费午夜 | 51国偷自产一区二区三区 | 在线观看国产一区二区三区 | a片在线免费观看 | 人妻尝试又大又粗久久 | 久久五月精品中文字幕 | 成人亚洲精品久久久久软件 | 精品无人区无码乱码毛片国产 | 欧美精品在线观看 | 日本精品少妇一区二区三区 | 人妻熟女一区 | 内射巨臀欧美在线视频 | 中文字幕乱码人妻二区三区 | 熟女俱乐部五十路六十路av | 国产精品欧美成人 | 久久99久久99精品中文字幕 | 久久99热只有频精品8 | 亚洲色欲久久久综合网东京热 | 日本爽爽爽爽爽爽在线观看免 | 欧美老人巨大xxxx做受 | 国产综合久久久久鬼色 | 精品少妇爆乳无码av无码专区 | 亚洲啪av永久无码精品放毛片 | 成人性做爰aaa片免费看 | 中文字幕久久久久人妻 | 天天躁日日躁狠狠躁免费麻豆 | 免费看男女做好爽好硬视频 | 婷婷丁香五月天综合东京热 | 国产av剧情md精品麻豆 | 国产又爽又猛又粗的视频a片 | 性欧美牲交xxxxx视频 | 久久精品国产日本波多野结衣 | 亚洲综合久久一区二区 | 国产精品对白交换视频 | 久久精品人人做人人综合试看 | 亚洲精品国产第一综合99久久 | 又湿又紧又大又爽a视频国产 | 亚洲精品中文字幕久久久久 | 久久天天躁夜夜躁狠狠 | 天天做天天爱天天爽综合网 | 久久精品中文字幕一区 | 久久99精品国产麻豆 | 免费无码午夜福利片69 | 国产激情无码一区二区 | 又大又硬又爽免费视频 | 无码人妻av免费一区二区三区 | 欧美精品国产综合久久 | 欧美成人免费全部网站 | 国产一区二区三区影院 | 无码帝国www无码专区色综合 | 国产suv精品一区二区五 | 99久久精品日本一区二区免费 | 国产精品久久久久久无码 | 精品国产一区二区三区av 性色 | 色情久久久av熟女人妻网站 | 色一情一乱一伦一区二区三欧美 | 未满小14洗澡无码视频网站 | 欧美日本精品一区二区三区 | 亚洲一区二区三区在线观看网站 | 少妇被黑人到高潮喷出白浆 | 两性色午夜视频免费播放 | 丰满人妻精品国产99aⅴ | 成人无码视频在线观看网站 | 四虎永久在线精品免费网址 | 国产成人无码av一区二区 | 日韩人妻无码一区二区三区久久99 | 亚洲欧美精品aaaaaa片 | 国产艳妇av在线观看果冻传媒 | 亚洲中文字幕av在天堂 | 丰满人妻翻云覆雨呻吟视频 | 久久精品视频在线看15 | 女人被爽到呻吟gif动态图视看 | 小鲜肉自慰网站xnxx | 国产一区二区三区影院 | 久久熟妇人妻午夜寂寞影院 | 亚洲熟妇色xxxxx亚洲 | 国产高清不卡无码视频 | 荫蒂被男人添的好舒服爽免费视频 | 国产成人av免费观看 | 婷婷综合久久中文字幕蜜桃三电影 | 亚洲午夜无码久久 | 欧美日韩久久久精品a片 | 欧美乱妇无乱码大黄a片 | www国产亚洲精品久久网站 | 伊人久久大香线蕉av一区二区 | 亚洲国产综合无码一区 | 国产偷国产偷精品高清尤物 | 亚洲熟熟妇xxxx | 日本熟妇浓毛 | 成人无码视频免费播放 | 国产高清av在线播放 | 一个人看的www免费视频在线观看 | 亚洲精品久久久久久久久久久 | 国产美女极度色诱视频www | 婷婷综合久久中文字幕蜜桃三电影 | 日本又色又爽又黄的a片18禁 | 日日鲁鲁鲁夜夜爽爽狠狠 | 2020久久超碰国产精品最新 | 亚洲日韩精品欧美一区二区 | 国产小呦泬泬99精品 | 亚洲日韩一区二区三区 | 99精品视频在线观看免费 | 亚洲人成影院在线无码按摩店 | 97夜夜澡人人爽人人喊中国片 | 妺妺窝人体色www在线小说 | 精品国精品国产自在久国产87 | 偷窥村妇洗澡毛毛多 | 青青久在线视频免费观看 | 狠狠色欧美亚洲狠狠色www | 成人女人看片免费视频放人 | 亚洲国产精品毛片av不卡在线 | 国产两女互慰高潮视频在线观看 | 少妇邻居内射在线 | 亚洲娇小与黑人巨大交 | 久久精品国产大片免费观看 | 亚洲综合久久一区二区 | 国产激情精品一区二区三区 | 少妇一晚三次一区二区三区 | 国产乱人无码伦av在线a | 亚洲成av人片天堂网无码】 | 国产av无码专区亚洲awww | 最近免费中文字幕中文高清百度 | 少女韩国电视剧在线观看完整 | 国产成人无码区免费内射一片色欲 | 精品乱子伦一区二区三区 | 国产成人无码av一区二区 | 久久97精品久久久久久久不卡 | 午夜福利电影 | 少妇高潮一区二区三区99 | 亚洲欧美日韩国产精品一区二区 | 久久精品视频在线看15 | 免费无码一区二区三区蜜桃大 | 东京热无码av男人的天堂 | 久久99精品久久久久久动态图 | 亚洲国产精品毛片av不卡在线 | 日韩欧美群交p片內射中文 | 午夜精品久久久久久久久 | 人人妻人人澡人人爽人人精品浪潮 | 无码任你躁久久久久久久 | 久久久精品456亚洲影院 | 国产亚洲日韩欧美另类第八页 | 久久精品国产99精品亚洲 | 麻豆国产丝袜白领秘书在线观看 | 日日麻批免费40分钟无码 | 日韩人妻系列无码专区 | 亚洲中文字幕乱码av波多ji | 无码av免费一区二区三区试看 | 在线 国产 欧美 亚洲 天堂 | 久久zyz资源站无码中文动漫 | 99久久精品国产一区二区蜜芽 | 欧美兽交xxxx×视频 | 日本一卡2卡3卡四卡精品网站 | 亚洲精品一区二区三区四区五区 | 日韩少妇内射免费播放 | 亚洲一区二区三区香蕉 | 国产精品多人p群无码 | 强辱丰满人妻hd中文字幕 | 国产69精品久久久久app下载 | 嫩b人妻精品一区二区三区 | 少妇高潮喷潮久久久影院 | 天干天干啦夜天干天2017 | 国产人妻久久精品二区三区老狼 | 久久国产精品精品国产色婷婷 | 一本久久伊人热热精品中文字幕 | 亚洲一区二区观看播放 | 日本xxxx色视频在线观看免费 | 成 人 网 站国产免费观看 | 少妇性l交大片欧洲热妇乱xxx | 中文字幕日韩精品一区二区三区 | 国产农村乱对白刺激视频 | 免费视频欧美无人区码 | 中文字幕乱妇无码av在线 | 欧美激情内射喷水高潮 | 亚洲国产精品毛片av不卡在线 | 国产成人午夜福利在线播放 | 亚洲aⅴ无码成人网站国产app | v一区无码内射国产 | 黑人玩弄人妻中文在线 | www国产精品内射老师 | 国产精品资源一区二区 | 十八禁真人啪啪免费网站 | 亚洲人成影院在线无码按摩店 | 国产欧美精品一区二区三区 | 色诱久久久久综合网ywww | 骚片av蜜桃精品一区 | 亚洲 激情 小说 另类 欧美 | 日本又色又爽又黄的a片18禁 | 97久久超碰中文字幕 | 麻花豆传媒剧国产免费mv在线 | 男人的天堂2018无码 | 色情久久久av熟女人妻网站 | 亚洲欧美日韩成人高清在线一区 | 樱花草在线社区www | 国产午夜亚洲精品不卡 | 成人影院yy111111在线观看 | 无码吃奶揉捏奶头高潮视频 | 玩弄中年熟妇正在播放 | 国产av一区二区三区最新精品 | 鲁大师影院在线观看 | 亚洲一区二区三区四区 | 在线播放无码字幕亚洲 | 国产精品美女久久久 | 亚洲色在线无码国产精品不卡 | 伊人久久大香线焦av综合影院 | 亚洲成色在线综合网站 | 乱人伦人妻中文字幕无码 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 丰满人妻翻云覆雨呻吟视频 | 久久天天躁狠狠躁夜夜免费观看 | 国产av久久久久精东av | 日韩少妇白浆无码系列 | 日本高清一区免费中文视频 | 久久精品人人做人人综合 | 97久久国产亚洲精品超碰热 | 国产一区二区三区精品视频 | 国产精品久久久久7777 | 久久精品女人的天堂av | 性欧美videos高清精品 | 欧美怡红院免费全部视频 | 无码帝国www无码专区色综合 | 影音先锋中文字幕无码 | 亚洲精品国产精品乱码视色 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 老熟妇乱子伦牲交视频 | 久久国产精品二国产精品 | 国产精品亚洲а∨无码播放麻豆 | 永久免费观看国产裸体美女 | 欧美人与物videos另类 | 色爱情人网站 | 亚洲欧美日韩综合久久久 | 夜精品a片一区二区三区无码白浆 | 日本一卡二卡不卡视频查询 | 亚洲s色大片在线观看 | 欧美日韩色另类综合 | 天天拍夜夜添久久精品大 | 美女极度色诱视频国产 | 欧美freesex黑人又粗又大 | 久久精品99久久香蕉国产色戒 | 成人免费视频视频在线观看 免费 | 国产欧美熟妇另类久久久 | 国产肉丝袜在线观看 | 老熟妇仑乱视频一区二区 | 亚洲国产精品美女久久久久 | 人妻体内射精一区二区三四 | 十八禁真人啪啪免费网站 | 中文字幕无码视频专区 | 一区二区三区乱码在线 | 欧洲 | 青春草在线视频免费观看 | 国产精品va在线观看无码 | 精品久久久久久人妻无码中文字幕 | 强开小婷嫩苞又嫩又紧视频 | 欧美日本免费一区二区三区 | 成 人 网 站国产免费观看 | 国产 精品 自在自线 | 国产精品自产拍在线观看 | 国产精品办公室沙发 | 55夜色66夜色国产精品视频 | 欧美人与牲动交xxxx | 爽爽影院免费观看 | 日本丰满护士爆乳xxxx | 97精品国产97久久久久久免费 | 中文字幕乱码人妻二区三区 | 麻豆av传媒蜜桃天美传媒 | 一本色道婷婷久久欧美 | 亚洲色在线无码国产精品不卡 | 黑人巨大精品欧美一区二区 | 天天av天天av天天透 | 国产精品毛片一区二区 | 东京无码熟妇人妻av在线网址 | 国产精品久久福利网站 | 国产性猛交╳xxx乱大交 国产精品久久久久久无码 欧洲欧美人成视频在线 | 无码av最新清无码专区吞精 | 亚洲日韩av一区二区三区四区 | 中文字幕无码日韩欧毛 | 中文字幕 亚洲精品 第1页 | 理论片87福利理论电影 | 久久无码中文字幕免费影院蜜桃 | 精品国产乱码久久久久乱码 | 久久99精品国产.久久久久 | 免费播放一区二区三区 | 久久久久se色偷偷亚洲精品av | 国产精品久久久久久亚洲影视内衣 | 亚洲欧美国产精品久久 | 婷婷五月综合缴情在线视频 | 狠狠色欧美亚洲狠狠色www | 国产色视频一区二区三区 | 在线亚洲高清揄拍自拍一品区 | 99久久精品国产一区二区蜜芽 | 亚洲va中文字幕无码久久不卡 | 日本免费一区二区三区最新 | 精品久久久久香蕉网 | 国产人成高清在线视频99最全资源 | 亚洲精品一区国产 | 波多野42部无码喷潮在线 | 自拍偷自拍亚洲精品被多人伦好爽 | 乌克兰少妇性做爰 | 色狠狠av一区二区三区 | 久久综合九色综合97网 | 欧美放荡的少妇 | 丰腴饱满的极品熟妇 | 国产精品久久久久久亚洲毛片 | 日韩人妻少妇一区二区三区 | 欧洲熟妇色 欧美 | 乱人伦中文视频在线观看 | 国产两女互慰高潮视频在线观看 | 亚洲一区二区三区香蕉 | 鲁一鲁av2019在线 | 亚洲中文无码av永久不收费 | 99久久久国产精品无码免费 | 天海翼激烈高潮到腰振不止 | 女人被男人爽到呻吟的视频 | 99久久人妻精品免费一区 | 国産精品久久久久久久 | 国内少妇偷人精品视频免费 | 牲交欧美兽交欧美 | 国产午夜亚洲精品不卡下载 | 永久免费观看国产裸体美女 | 人人妻人人澡人人爽人人精品浪潮 | 亚洲色偷偷男人的天堂 | 狠狠亚洲超碰狼人久久 | 欧美国产日产一区二区 | 国产麻豆精品一区二区三区v视界 | 老熟妇仑乱视频一区二区 | 欧美老人巨大xxxx做受 | 亚洲国产欧美日韩精品一区二区三区 | 成人三级无码视频在线观看 | 欧美性生交xxxxx久久久 | 人妻尝试又大又粗久久 | 欧洲vodafone精品性 | 日本成熟视频免费视频 | 又湿又紧又大又爽a视频国产 | 免费国产成人高清在线观看网站 | 国语自产偷拍精品视频偷 | 激情内射日本一区二区三区 | 天堂亚洲2017在线观看 | 国产97色在线 | 免 | 成人精品视频一区二区三区尤物 | 色综合久久中文娱乐网 | 日韩av无码一区二区三区 | 亚洲乱码中文字幕在线 | 国产成人精品一区二区在线小狼 | 精品国产麻豆免费人成网站 | 一区二区传媒有限公司 | 亚洲成av人片天堂网无码】 | 内射欧美老妇wbb | 理论片87福利理论电影 | 亚洲 另类 在线 欧美 制服 | 国产av无码专区亚洲a∨毛片 | 伊在人天堂亚洲香蕉精品区 | 波多野结衣 黑人 | 欧洲精品码一区二区三区免费看 | 国产精品嫩草久久久久 | 亚洲中文字幕va福利 | 精品无码国产自产拍在线观看蜜 | 欧美35页视频在线观看 | 亚洲第一网站男人都懂 | 性开放的女人aaa片 | 免费观看又污又黄的网站 | 精品国产一区二区三区四区在线看 | 日本xxxx色视频在线观看免费 | 西西人体www44rt大胆高清 | 欧美成人高清在线播放 | 免费人成在线视频无码 | 久久99热只有频精品8 | 亚洲一区二区三区播放 | 老头边吃奶边弄进去呻吟 | 国产精品亚洲专区无码不卡 | 亚洲男人av香蕉爽爽爽爽 | 好男人www社区 | 无套内谢的新婚少妇国语播放 | 国产成人无码区免费内射一片色欲 | 熟妇人妻无乱码中文字幕 | 国内精品九九久久久精品 | 久久综合给久久狠狠97色 | 国产三级精品三级男人的天堂 | 精品国产aⅴ无码一区二区 | 日韩人妻无码中文字幕视频 | 无码纯肉视频在线观看 | 帮老师解开蕾丝奶罩吸乳网站 | 麻豆蜜桃av蜜臀av色欲av | 成 人 网 站国产免费观看 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 狠狠色噜噜狠狠狠7777奇米 | 少妇人妻偷人精品无码视频 | 成人无码视频在线观看网站 | 亚洲熟悉妇女xxx妇女av | 亚洲精品综合一区二区三区在线 | 久久久久久国产精品无码下载 | 99国产精品白浆在线观看免费 | 永久免费精品精品永久-夜色 | 永久免费精品精品永久-夜色 | 日韩精品乱码av一区二区 | 国产亚洲精品精品国产亚洲综合 | 人人妻人人澡人人爽精品欧美 | 国产suv精品一区二区五 | 未满小14洗澡无码视频网站 | 国产片av国语在线观看 | 亚洲伊人久久精品影院 | 成人无码视频免费播放 | 草草网站影院白丝内射 | 亚洲の无码国产の无码步美 | 久久午夜无码鲁丝片 | 亚洲成熟女人毛毛耸耸多 | 国产乱子伦视频在线播放 | 中文字幕人成乱码熟女app | 无码任你躁久久久久久久 | 欧美日本精品一区二区三区 | 久精品国产欧美亚洲色aⅴ大片 | 欧美成人午夜精品久久久 | 亚洲 另类 在线 欧美 制服 | 亚洲 激情 小说 另类 欧美 | 久久久久久av无码免费看大片 | 亚洲中文字幕成人无码 | 国产成人人人97超碰超爽8 | 亚洲精品无码人妻无码 | 夜夜影院未满十八勿进 | 国产精品久免费的黄网站 | 国产婷婷色一区二区三区在线 | 久久久久久久人妻无码中文字幕爆 | 麻豆人妻少妇精品无码专区 | 日日麻批免费40分钟无码 | 麻豆成人精品国产免费 | 久久精品国产一区二区三区 | 麻豆国产丝袜白领秘书在线观看 | 国产亚洲精品久久久久久久久动漫 | 欧美亚洲日韩国产人成在线播放 | 少妇无套内谢久久久久 | 人人澡人摸人人添 | 久久zyz资源站无码中文动漫 | 麻豆果冻传媒2021精品传媒一区下载 | 国产乱人伦av在线无码 | 无码人妻黑人中文字幕 | 国产精品成人av在线观看 | 免费国产成人高清在线观看网站 | 精品国产麻豆免费人成网站 | 久久亚洲精品中文字幕无男同 | 草草网站影院白丝内射 | 熟妇人妻激情偷爽文 | 丁香花在线影院观看在线播放 | 97久久超碰中文字幕 | 国产精品久久久久久无码 | 亚洲国产精品毛片av不卡在线 | 在线a亚洲视频播放在线观看 | 97无码免费人妻超级碰碰夜夜 | 欧美野外疯狂做受xxxx高潮 | 亚洲日本一区二区三区在线 | 亚洲 a v无 码免 费 成 人 a v | 帮老师解开蕾丝奶罩吸乳网站 | 一本精品99久久精品77 | 麻豆精品国产精华精华液好用吗 | 人妻少妇精品无码专区动漫 | 亚洲一区二区三区偷拍女厕 | 成人女人看片免费视频放人 | 亚洲娇小与黑人巨大交 | 国产精品久久国产三级国 | 国产av剧情md精品麻豆 | 久久精品国产日本波多野结衣 | 国产亚洲精品精品国产亚洲综合 | 激情国产av做激情国产爱 | 性色av无码免费一区二区三区 | 精品久久综合1区2区3区激情 | 日本精品少妇一区二区三区 | 久久精品无码一区二区三区 | 免费网站看v片在线18禁无码 | 国产成人无码一二三区视频 | av无码久久久久不卡免费网站 | 精品熟女少妇av免费观看 | 性生交片免费无码看人 | 婷婷五月综合缴情在线视频 | 澳门永久av免费网站 | 欧美日韩综合一区二区三区 | 99精品无人区乱码1区2区3区 | 特级做a爰片毛片免费69 | a国产一区二区免费入口 | 国产欧美精品一区二区三区 | 国产精品99久久精品爆乳 | 久久综合色之久久综合 | 国产日产欧产精品精品app | 国产超碰人人爽人人做人人添 | 一本久久a久久精品vr综合 | 亚洲精品午夜无码电影网 | 丰满妇女强制高潮18xxxx | 亚洲成a人片在线观看无码 | 熟妇人妻无码xxx视频 | 黑人巨大精品欧美黑寡妇 | 丁香花在线影院观看在线播放 | 亚洲色大成网站www国产 | 99国产欧美久久久精品 | 国产一区二区三区精品视频 | 成人无码影片精品久久久 | 欧美兽交xxxx×视频 | 国产精品人人爽人人做我的可爱 | 国产深夜福利视频在线 | 日本乱人伦片中文三区 | 亚洲色大成网站www国产 | 粉嫩少妇内射浓精videos | 少妇性俱乐部纵欲狂欢电影 | 久久国语露脸国产精品电影 | 熟女少妇在线视频播放 | 国产精品无套呻吟在线 | 国产精品人妻一区二区三区四 | 国产精品va在线观看无码 | 伊人久久婷婷五月综合97色 | 成人亚洲精品久久久久软件 | 久久久久亚洲精品男人的天堂 | 国产片av国语在线观看 | 国产熟妇高潮叫床视频播放 | 久久亚洲国产成人精品性色 | 无码吃奶揉捏奶头高潮视频 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 俺去俺来也在线www色官网 | 亚洲日韩av一区二区三区四区 | 欧美freesex黑人又粗又大 | 日韩精品成人一区二区三区 | 亚洲欧美国产精品专区久久 | 18禁黄网站男男禁片免费观看 | 亚洲男人av香蕉爽爽爽爽 | 思思久久99热只有频精品66 | 久久久久久久久888 | 久久精品国产一区二区三区 | 玩弄人妻少妇500系列视频 | 初尝人妻少妇中文字幕 | 无码精品人妻一区二区三区av | 国产偷自视频区视频 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 亚洲国产av美女网站 | 日本www一道久久久免费榴莲 | 国产成人综合在线女婷五月99播放 | 女人被爽到呻吟gif动态图视看 | 国产肉丝袜在线观看 | 亚洲国产欧美在线成人 | 正在播放老肥熟妇露脸 | 男女下面进入的视频免费午夜 | 久久国产36精品色熟妇 | 久久精品中文闷骚内射 | 少妇厨房愉情理9仑片视频 | 3d动漫精品啪啪一区二区中 | 2020久久超碰国产精品最新 | 十八禁视频网站在线观看 | 国产人妻精品午夜福利免费 | 欧美肥老太牲交大战 | 欧美成人免费全部网站 | 国产精品无码成人午夜电影 | 亚洲色www成人永久网址 | 久久人妻内射无码一区三区 | 青青久在线视频免费观看 | 免费国产黄网站在线观看 | 日本又色又爽又黄的a片18禁 | 国产精品久久久久久无码 | 精品国偷自产在线视频 | 国产情侣作爱视频免费观看 | 久久人人爽人人爽人人片ⅴ | 午夜精品久久久久久久久 | 无码人妻少妇伦在线电影 | 无套内谢的新婚少妇国语播放 | 三上悠亚人妻中文字幕在线 | 国产精华av午夜在线观看 | 久久亚洲中文字幕精品一区 | 成人试看120秒体验区 | 成在人线av无码免观看麻豆 | 国产农村妇女高潮大叫 | 福利一区二区三区视频在线观看 | 2020久久香蕉国产线看观看 | 久久久av男人的天堂 | 国产精品人人妻人人爽 | 亚洲中文字幕在线无码一区二区 | 国内少妇偷人精品视频免费 | 99久久人妻精品免费二区 | 欧美老熟妇乱xxxxx | 亚洲国产精品无码久久久久高潮 | 成人无码视频免费播放 | 国产精品自产拍在线观看 | 亚洲爆乳大丰满无码专区 | 国产精品第一国产精品 | 亚洲一区二区三区含羞草 | 亚洲自偷精品视频自拍 | 国产成人无码午夜视频在线观看 | 久久99精品久久久久婷婷 | 久久99精品国产麻豆 | 精品熟女少妇av免费观看 | 久久久久亚洲精品男人的天堂 | 婷婷五月综合缴情在线视频 | 精品欧洲av无码一区二区三区 | 亚洲色欲久久久综合网东京热 | 国色天香社区在线视频 | 国产精华av午夜在线观看 | 免费国产黄网站在线观看 | 99久久精品午夜一区二区 | 国产成人无码av片在线观看不卡 | 无遮挡国产高潮视频免费观看 | 成人综合网亚洲伊人 | 99久久精品国产一区二区蜜芽 | 国精品人妻无码一区二区三区蜜柚 | 无码人妻精品一区二区三区不卡 | 性欧美牲交xxxxx视频 | 小sao货水好多真紧h无码视频 | 久久精品人人做人人综合 | 中文字幕av伊人av无码av | 国产精品igao视频网 | 高潮喷水的毛片 | 秋霞特色aa大片 | 精品无人区无码乱码毛片国产 | 中文字幕av无码一区二区三区电影 | 久久人人爽人人爽人人片ⅴ | 欧美激情综合亚洲一二区 | 亚洲精品一区国产 | 国产午夜福利100集发布 | √天堂资源地址中文在线 | 人人爽人人澡人人高潮 | 国产精品怡红院永久免费 | av无码久久久久不卡免费网站 | 99久久精品午夜一区二区 | 精品国产一区二区三区四区 | 99麻豆久久久国产精品免费 | 亚洲欧美精品aaaaaa片 | 中文字幕+乱码+中文字幕一区 | 国产亚洲精品久久久久久国模美 | 少女韩国电视剧在线观看完整 | 澳门永久av免费网站 | 一本色道久久综合亚洲精品不卡 | 亚洲精品国产精品乱码视色 | 99riav国产精品视频 | 国内丰满熟女出轨videos | 宝宝好涨水快流出来免费视频 | 4hu四虎永久在线观看 | 免费视频欧美无人区码 | 国产热a欧美热a在线视频 | 青青青爽视频在线观看 | 亚洲国产精品无码一区二区三区 | 大地资源中文第3页 | 久久国产精品萌白酱免费 | 人妻夜夜爽天天爽三区 | 亚洲精品成人福利网站 | 99精品视频在线观看免费 | 一本久久a久久精品亚洲 | 精品aⅴ一区二区三区 | 无码国产激情在线观看 | 大乳丰满人妻中文字幕日本 | 久久亚洲日韩精品一区二区三区 | 亚洲精品国偷拍自产在线麻豆 | 中文字幕日韩精品一区二区三区 | 精品欧洲av无码一区二区三区 | 九九综合va免费看 | 国产精品亚洲lv粉色 | 黑人巨大精品欧美一区二区 | 国产亚洲视频中文字幕97精品 | 一二三四社区在线中文视频 | 国产综合色产在线精品 | 香港三级日本三级妇三级 | 亚洲色成人中文字幕网站 | 国产麻豆精品精东影业av网站 | 日韩精品久久久肉伦网站 | 亚洲中文无码av永久不收费 | 丰腴饱满的极品熟妇 | 中文字幕乱码亚洲无线三区 | 无码精品国产va在线观看dvd | 麻花豆传媒剧国产免费mv在线 | 国产亚洲精品久久久闺蜜 | 乱人伦人妻中文字幕无码 | 激情内射日本一区二区三区 | 精品欧洲av无码一区二区三区 | 久久99热只有频精品8 | 在线播放亚洲第一字幕 | 亚洲成av人综合在线观看 | 亚洲国产成人av在线观看 | 亚洲日本va中文字幕 | 久久精品国产一区二区三区 | 人妻无码αv中文字幕久久琪琪布 | 国产免费无码一区二区视频 | 日韩人妻无码中文字幕视频 | 日本精品少妇一区二区三区 | 99国产欧美久久久精品 | 国产av久久久久精东av | 狠狠色噜噜狠狠狠7777奇米 | 欧美35页视频在线观看 | www国产精品内射老师 | 黑人巨大精品欧美黑寡妇 | 成人欧美一区二区三区黑人免费 | 久久久久亚洲精品男人的天堂 | 欧美黑人性暴力猛交喷水 | 人人爽人人澡人人高潮 | 午夜免费福利小电影 | 国产97在线 | 亚洲 | 麻豆国产丝袜白领秘书在线观看 | 人人澡人摸人人添 | 成年女人永久免费看片 | 色偷偷人人澡人人爽人人模 | 高清不卡一区二区三区 | 久久人妻内射无码一区三区 | 在线欧美精品一区二区三区 | 天天燥日日燥 | 婷婷六月久久综合丁香 | 荫蒂被男人添的好舒服爽免费视频 | 国产精品久久福利网站 | 国产又爽又猛又粗的视频a片 | 高清不卡一区二区三区 | 女人被爽到呻吟gif动态图视看 | 国产成人人人97超碰超爽8 | 国产精品va在线观看无码 | 亚洲精品一区二区三区在线观看 | 久久熟妇人妻午夜寂寞影院 | 一个人看的视频www在线 | 成年美女黄网站色大免费全看 | 国产成人无码区免费内射一片色欲 | 久久伊人色av天堂九九小黄鸭 | 国产97色在线 | 免 | 性欧美videos高清精品 | 内射白嫩少妇超碰 | 天天拍夜夜添久久精品大 | 国产明星裸体无码xxxx视频 | 秋霞成人午夜鲁丝一区二区三区 | 色诱久久久久综合网ywww | 在线 国产 欧美 亚洲 天堂 | 台湾无码一区二区 | 亚洲成熟女人毛毛耸耸多 | 欧美日韩色另类综合 | 欧美xxxx黑人又粗又长 | 午夜福利一区二区三区在线观看 | 成人性做爰aaa片免费看 | 久久国产自偷自偷免费一区调 | 午夜精品久久久内射近拍高清 | 国产亚洲精品久久久ai换 | 亚洲成a人片在线观看无码 | 久久综合香蕉国产蜜臀av | 亚洲精品一区二区三区大桥未久 | 亚洲精品一区二区三区在线观看 | 黑人粗大猛烈进出高潮视频 | 精品少妇爆乳无码av无码专区 | 精品成人av一区二区三区 | 成人欧美一区二区三区 | 久久99热只有频精品8 | 最近免费中文字幕中文高清百度 | 久久久av男人的天堂 | 天天av天天av天天透 | 西西人体www44rt大胆高清 | 人妻体内射精一区二区三四 | aa片在线观看视频在线播放 | 97夜夜澡人人双人人人喊 | 中文字幕无码免费久久99 | 亚洲国产精品无码一区二区三区 | 亚洲日韩av一区二区三区四区 | 日本熟妇乱子伦xxxx | 日本在线高清不卡免费播放 | 人妻少妇精品无码专区二区 | 人妻中文无码久热丝袜 | 日本免费一区二区三区最新 | 中文字幕精品av一区二区五区 | 蜜桃视频插满18在线观看 | 国产精品久久久久久无码 | 亚洲男人av香蕉爽爽爽爽 | 人妻无码αv中文字幕久久琪琪布 | 日本熟妇乱子伦xxxx | 中文毛片无遮挡高清免费 | 无码人中文字幕 | 日韩av无码一区二区三区不卡 | 久久99久久99精品中文字幕 | 特级做a爰片毛片免费69 | 国内老熟妇对白xxxxhd | 久久久久av无码免费网 | 激情内射亚州一区二区三区爱妻 | 免费无码午夜福利片69 | 少妇的肉体aa片免费 | 国产精品毛多多水多 | 131美女爱做视频 | 人人爽人人爽人人片av亚洲 | 色噜噜亚洲男人的天堂 | 国精品人妻无码一区二区三区蜜柚 | 久久国内精品自在自线 | 十八禁视频网站在线观看 | 又粗又大又硬毛片免费看 | 67194成是人免费无码 | 亚洲色无码一区二区三区 | 欧美熟妇另类久久久久久多毛 | 成人女人看片免费视频放人 | 377p欧洲日本亚洲大胆 | 亚洲啪av永久无码精品放毛片 | 国产激情无码一区二区 | 亚洲一区av无码专区在线观看 | 天堂一区人妻无码 | 人妻人人添人妻人人爱 | 无套内谢老熟女 | 亚洲 高清 成人 动漫 | 狠狠色噜噜狠狠狠7777奇米 | 牛和人交xxxx欧美 | 久久精品无码一区二区三区 | 88国产精品欧美一区二区三区 | 国内精品久久毛片一区二区 | 漂亮人妻洗澡被公强 日日躁 | 久久国产精品_国产精品 | 麻豆精品国产精华精华液好用吗 | 2020久久香蕉国产线看观看 | 精品aⅴ一区二区三区 | 国产亚洲精品久久久久久久 | 国语精品一区二区三区 | 99精品久久毛片a片 | 国产人妻精品一区二区三区 | 漂亮人妻洗澡被公强 日日躁 | 人妻天天爽夜夜爽一区二区 | 欧美午夜特黄aaaaaa片 | 欧洲熟妇色 欧美 | 亚洲熟女一区二区三区 | 欧洲熟妇精品视频 | 亚洲最大成人网站 | 中文字幕+乱码+中文字幕一区 | 亚洲热妇无码av在线播放 | 久久熟妇人妻午夜寂寞影院 | 丰满人妻一区二区三区免费视频 | 国产精品a成v人在线播放 | 国产成人精品久久亚洲高清不卡 | 亚洲 日韩 欧美 成人 在线观看 | 大地资源网第二页免费观看 | 亚洲欧美国产精品专区久久 | 色狠狠av一区二区三区 | 沈阳熟女露脸对白视频 | 免费视频欧美无人区码 | 欧美性猛交xxxx富婆 | 日产精品99久久久久久 | 一本一道久久综合久久 | 伊人久久大香线焦av综合影院 | 中文字幕人成乱码熟女app | 亚洲男女内射在线播放 | 亚洲热妇无码av在线播放 | 中文字幕乱妇无码av在线 | 激情爆乳一区二区三区 | 欧美国产亚洲日韩在线二区 | 牲欲强的熟妇农村老妇女 | 7777奇米四色成人眼影 | 最近中文2019字幕第二页 | 国产一区二区三区影院 | 日本大香伊一区二区三区 | 国产精品人人妻人人爽 | 任你躁国产自任一区二区三区 | 国产亚洲tv在线观看 | 丰腴饱满的极品熟妇 | 精品人妻中文字幕有码在线 | 99久久人妻精品免费一区 | 亚洲最大成人网站 | 麻豆国产人妻欲求不满谁演的 | 强伦人妻一区二区三区视频18 | 欧洲美熟女乱又伦 | 亚洲国产高清在线观看视频 | 婷婷丁香五月天综合东京热 | 领导边摸边吃奶边做爽在线观看 | 欧美老妇交乱视频在线观看 | 国产亚洲精品久久久久久久久动漫 | 67194成是人免费无码 | 亚洲国产成人a精品不卡在线 | 久久99精品久久久久久动态图 | 丝袜美腿亚洲一区二区 | 国产明星裸体无码xxxx视频 | yw尤物av无码国产在线观看 | 国产亚洲欧美日韩亚洲中文色 | 亚洲日韩av一区二区三区四区 | 亚洲码国产精品高潮在线 | 国产农村乱对白刺激视频 | 亚洲午夜久久久影院 | 黄网在线观看免费网站 | 亚洲区小说区激情区图片区 | 影音先锋中文字幕无码 | 丝袜 中出 制服 人妻 美腿 | 日本熟妇大屁股人妻 | 欧美日韩一区二区三区自拍 | 久久久久久久女国产乱让韩 | 国产国语老龄妇女a片 | 精品久久8x国产免费观看 | 在线成人www免费观看视频 | 乱码午夜-极国产极内射 | 久久99精品国产麻豆 | 久久综合给合久久狠狠狠97色 | 久久精品国产99精品亚洲 | 成人免费视频视频在线观看 免费 | 国产精品永久免费视频 | √天堂资源地址中文在线 | 国产精品无码成人午夜电影 | a片免费视频在线观看 | ass日本丰满熟妇pics | 1000部啪啪未满十八勿入下载 | 国产精品自产拍在线观看 | 99久久无码一区人妻 | 国产高清av在线播放 | aⅴ亚洲 日韩 色 图网站 播放 | 乱中年女人伦av三区 | 人妻与老人中文字幕 | 无码国产色欲xxxxx视频 | 久久久无码中文字幕久... | 无人区乱码一区二区三区 | 麻豆精品国产精华精华液好用吗 | 久久人人爽人人爽人人片av高清 | 青草青草久热国产精品 | 日本精品高清一区二区 | 久久久www成人免费毛片 | 国产欧美亚洲精品a | 免费无码的av片在线观看 | 最近的中文字幕在线看视频 | 蜜臀aⅴ国产精品久久久国产老师 | 亚洲精品国产精品乱码不卡 | 国产精品高潮呻吟av久久4虎 | 九九综合va免费看 | 在线a亚洲视频播放在线观看 | 精品水蜜桃久久久久久久 | yw尤物av无码国产在线观看 | 精品一二三区久久aaa片 | 给我免费的视频在线观看 | 精品欧美一区二区三区久久久 | 国产精品鲁鲁鲁 | 国产农村乱对白刺激视频 | 老熟女重囗味hdxx69 | 台湾无码一区二区 | 无码乱肉视频免费大全合集 | 国产精品亚洲а∨无码播放麻豆 | 午夜精品久久久久久久久 | 少妇厨房愉情理9仑片视频 | 无遮挡国产高潮视频免费观看 | 嫩b人妻精品一区二区三区 | 成人一在线视频日韩国产 | 亚洲精品久久久久久一区二区 | 狂野欧美性猛交免费视频 | 亚拍精品一区二区三区探花 | 美女极度色诱视频国产 | 亚洲 日韩 欧美 成人 在线观看 | 欧美第一黄网免费网站 | 日韩av无码一区二区三区不卡 | av无码电影一区二区三区 | 成 人 网 站国产免费观看 | aⅴ亚洲 日韩 色 图网站 播放 | 激情人妻另类人妻伦 | 偷窥日本少妇撒尿chinese | 精品人妻人人做人人爽夜夜爽 | 亚洲中文字幕av在天堂 | 成年美女黄网站色大免费全看 | 99国产欧美久久久精品 | 亚洲熟悉妇女xxx妇女av | 玩弄人妻少妇500系列视频 | 国产精品人妻一区二区三区四 |