日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Java 和操作系统交互,你猜会发生什么?

發布時間:2025/3/21 windows 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 和操作系统交互,你猜会发生什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:lonelysnow

鏈接:https://www.jianshu.com/p/7f6832d61880

結合 CPU 理解一行 Java 代碼是怎么執行的

根據馮·諾依曼思想,計算機采用二進制作為數制基礎,必須包含:運算器、控制器、存儲設備,以及輸入輸出設備,如下圖所示。

(該圖來源于百度)

我們先來分析 CPU 的工作原理,現代 CPU 芯片中大都集成了,控制單元,運算單元,存儲單元.控制單元是 CPU 的控制中心, CPU 需要通過它才知道下一步做什么,也就是執行什么指令,控制單元又包含:指令寄存器( IR ),指令譯碼器( ID )和操作控制器( OC )。

當程序被加載進內存后,指令就在內存中了,這個時候說的內存是獨立于 CPU 外的主存設備,也就是 PC 機中的內存條,指令指針寄存器IP 指向內存中下一條待執行指令的地址,控制單元根據 IP寄存器的指向,將主存中的指令裝載到指令寄存器,這個指令寄存器也是一個存儲設備,不過他集成在 CPU 內部。

指令從主存到達 CPU 后只是一串 010101 的二進制串,還需要通過譯碼器解碼,分析出操作碼是什么,操作數在哪,之后就是具體的運算單元進行算術運算(加減乘除),邏輯運算(比較,位移).而 CPU 指令執行過程大致為:取址(去主存獲取指令放到寄存器),譯碼(從主存獲取操作數放入高速緩存 L1 ),執行(運算)。

這里解釋下上圖中 CPU 內部集成的存儲單元 SRAM ,正好和主存中的 DRAM 對應, RAM 是隨機訪問內存,就是給一個地址就能訪問到數據,而磁盤這種存儲媒介必須順序訪問,而 RAM 又分為動態和靜態兩種,靜態 RAM 由于集成度較低,一般容量小,速度快,而動態 RAM 集成度較高,主要通過給電容充電和放電實現,速度沒有靜態 RAM 快,所以一般將動態 RAM 做為主存,而靜態 RAM 作為 CPU 和主存之間的高速緩存(cache),用來屏蔽 CPU 和主存速度上的差異,也就是我們經常看到的 L1 , L2 緩存.每一級別緩存速度變低,容量變大。

下圖展示了存儲器的層次化架構,以及 CPU 訪問主存的過程,這里有兩個知識點,一個是多級緩存之間為保證數據的一致性,而推出的緩存一致性協議,具體可以參考這篇文章,另外一個知識點是, cache 和主存的映射,首先要明確的是 cahce 緩存的單位是緩存行,對應主存中的一個內存塊,并不是一個變量,這個主要是因為 ** CPU 訪問的空間局限性:被訪問的某個存儲單元,在一個較短時間內,很有可能再次被訪問到,以及空間局限性:被訪問的某個存儲單元,在較短時間內,他的相鄰存儲單元也會被訪問到。**

而映射方式有很多種,類似于 cache 行號 = 主存塊號 mod cache總行數 ,這樣每次獲取到一個主存地址,根據這個地址計算出在主存中的塊號就可以計算出在 cache 中的行號。

下面我們接著聊 CPU 的指令執行.取址,譯碼,執行,這是一個指令的執行過程,所有指令都會嚴格按照這個順序執行,但是多個指令之間其實是可以并行的,對于單核 CPU 來說,同一時刻只能有一條指令能夠占有執行單元運行,這里說的執行是 CPU 指令處理(取指,譯碼,執行)三步驟中的第三步,也就是運算單元的計算任務,所以為了提升 CPU 的指令處理速度。

所以需要保證運算單元在執行前的準備工作都完成,這樣運算單元就可以一直處于運算中,而剛剛的串行流程中,取指,解碼的時候運算單元是空閑的,而且取指和解碼如果沒有命中高速緩存還需要從主存取,而主存的速度和 CPU 不在一個級別上,所以指令流水線?可以大大提高 CPU 的處理速度,下圖是一個3級流水線的示例圖,而現在的奔騰 CPU 都是32級流水線,具體做法就是將上面三個流程拆分的更細。

除了指令流水線, CPU 還有分支預測,亂序執行等優化速度的手段.好了,我們回到正題,一行 Java 代碼是怎么執行的。

一行代碼能夠執行,必須要有可以執行的上下文環境,包括,指令寄存器,數據寄存器,棧空間等內存資源,然后這行代碼必須作為一個執行流能夠被操作系統的任務調度器識別,并給他分配 CPU 資源,當然這行代碼所代表的指令必須是 CPU 可以解碼識別的,所以一行 Java 代碼必須被解釋成對應的 CPU 指令才能執行.下面我們看下System.out.println("Hello world")這行代碼的轉譯過程。

Java 是一門高級語言,這類語言不能直接運行在硬件上,必須運行在能夠識別 Java 語言特性的虛擬機上,而 Java 代碼必須通過 Java 編譯器將其轉換成虛擬機所能識別的指令序列,也稱為 Java 字節碼,之所以稱為字節碼是因為 Java 字節碼的操作指令(OpCode)被固定為一個字節,以下為 System.out.println("Hello world") 編譯后的字節碼。

0x00:??b2?00?02?????????getstatic??Java?.lang.System.out 0x03:??12?03????????????ldc?"Hello,?World!" 0x05:??b6?00?04?????????invokevirtual??Java?.io.PrintStream.println 0x08:??b1???????????????return

最左列是偏移;中間列是給虛擬機讀的字節碼;最右列是高級語言的代碼,下面是通過匯編語言轉換成的機器指令,中間是機器碼,第三列為對應的機器指令,最后一列是對應的匯編代碼。

0x00:??55????????????????????push???rbp 0x01:??48?89?e5??????????????mov????rbp,rsp 0x04:??48?83?ec?10???????????sub????rsp,0x10 0x08:??48?8d?3d?3b?00?00?00??lea????rdi,[rip+0x3b];?加載?"Hello,?World! " 0x0f:??c7?45?fc?00?00?00?00??mov????DWORD?PTR?[rbp-0x4],0x0 0x16:??b0?00?????????????????mov????al,0x0 0x18:??e8?0d?00?00?00????????call???0x12;?調用?printf?方法 0x1d:??31?c9?????????????????xor????ecx,ecx 0x1f:??89?45?f8??????????????mov????DWORD?PTR?[rbp-0x8],eax 0x22:??89?c8?????????????????mov????eax,ecx 0x24:??48?83?c4?10???????????add????rsp,0x10 0x28:??5d????????????????????pop????rbp 0x29:??c3????????????????????ret

JVM 通過類加載器加載 class 文件里的字節碼后,會通過解釋器解釋成匯編指令,最終再轉譯成 CPU 可以識別的機器指令,解釋器是軟件來實現的,主要是為了實現同一份 Java 字節碼可以在不同的硬件平臺上運行。

而將匯編指令轉換成機器指令由硬件直接實現,這一步速度是很快的,當然 JVM 為了提高運行效率也可以將某些熱點代碼(一個方法內的代碼)一次全部編譯成機器指令后然后在執行,也就是和解釋執行對應的即時編譯(JIT), JVM 啟動的時候可以通過 -Xint 和 -Xcomp 來控制執行模式。

從軟件層面上, class 文件被加載進虛擬機后,類信息會存放在方法區,在實際運行的時候會執行方法區中的代碼,在 JVM 中所有的線程共享堆內存和方法區,而每個線程有自己獨立的 Java 方法棧。

本地方法棧(面向 native 方法),PC寄存器(存放線程執行位置),當調用一個方法的時候, Java 虛擬機會在當前線程對應的方法棧中壓入一個棧幀,用來存放 Java 字節碼操作數以及局部變量,這個方法執行完會彈出棧幀,一個線程會連續執行多個方法,對應不同的棧幀的壓入和彈出,壓入棧幀后就是 JVM 解釋執行的過程了。

中斷

剛剛說到, CPU 只要一上電就像一個永動機, 不停的取指令,運算,周而復始,而中斷便是操作系統的靈魂,故名思議,中斷就是打斷 CPU 的執行過程,轉而去做點別的,例如系統執行期間發生了致命錯誤,需要結束執行,例如用戶程序調用了一個系統調用的方法,例如mmp等,就會通過中斷讓 CPU 切換上下文,轉到內核空間。

例如一個等待用戶輸入的程序正在阻塞,而當用戶通過鍵盤完成輸入,內核數據已經準備好后,就會發一個中斷信號,喚醒用戶程序把數據從內核取走,不然內核可能會數據溢出,當磁盤報了一個致命異常,也會通過中斷通知 CPU ,定時器完成時鐘滴答也會發時鐘中斷通知 CPU 。

中斷的種類,我們這里就不做細分了,中斷有點類似于我們經常說的事件驅動編程,而這個事件通知機制是怎么實現的呢,硬件中斷的實現通過一個導線和 CPU 相連來傳輸中斷信號,軟件上會有特定的指令。

例如執行系統調用創建線程的指令,而 CPU 每執行完一個指令,就會檢查中斷寄存器中是否有中斷,如果有就取出然后執行該中斷對應的處理程序。

陷入內核 : 我們在設計軟件的時候,會考慮程序上下文切換的頻率,頻率太高肯定會影響程序執行性能,而陷入內核是針對 CPU 而言的, CPU 的執行從用戶態轉向內核態,以前是用戶程序在使用 CPU ,現在是內核程序在使用 CPU ,這種切換是通過系統調用產生的,系統調用是執行操作系統底層的程序。

Linux的設計者,為了保護操作系統,將進程的執行狀態用內核態和用戶態分開,同一個進程中,內核和用戶共享同一個地址空間,一般 4G 的虛擬地址,其中 1G 給內核態, 3G 給用戶態.在程序設計的時候我們要盡量減少用戶態到內核態的切換,例如創建線程是一個系統調用,所以我們有了線程池的實現。

從 Linux 內存管理角度理解 JVM 內存模型

進程上下文

我們可以將程序理解為一段可執行的指令集合,而這個程序啟動后,操作系統就會為他分配 CPU ,內存等資源,而這個正在運行的程序就是我們說的進程,進程是操作系統對處理器中運行的程序的一種抽象,而為進程分配的內存以及 CPU 資源就是這個進程的上下文,保存了當前執行的指令,以及變量值。

而 JVM 啟動后也是linux上的一個普通進程,進程的物理實體和支持進程運行的環境合稱為上下文,而上下文切換就是將當前正在運行的進程換下,換一個新的進程到處理器運行,以此來讓多個進程并發的執行,上下文切換可能來自操作系統調度,也有可能來自程序內部,例如讀取IO的時候,會讓用戶代碼和操作系統代碼之間進行切換。

虛擬存儲

當我們同時啟動多個 JVM 執行: System.out.println(new Object()); 將會打印這個對象的 hashcode ,hashcode 默認為內存地址,最后發現他們打印的都是 ?Java .lang.Object@4fca772d ,也就是多個進程返回的內存地址竟然是一樣的。

通過上面的例子我們可以證明,linux中每個進程有單獨的地址空間,在此之前,我們先了解下 CPU 是如何訪問內存的?

假設我們現在還沒有虛擬地址,只有物理地址,編譯器在編譯程序的時候,需要將高級語言轉換成機器指令,那么 CPU 訪問內存的時候必須指定一個地址,這個地址如果是一個絕對的物理地址,那么程序就必須放在內存中的一個固定的地方,而且這個地址需要在編譯的時候就要確認。

大家應該想到這樣有多坑了吧, 如果我要同時運行兩個 office word 程序,那么他們將操作同一塊內存,那就亂套了,偉大的計算機前輩設計出,讓 CPU 采用 段基址 + 段內偏移地址 的方式訪問內存,其中段基地址在程序啟動的時候確認,盡管這個段基地址還是絕對的物理地址,但終究可以同時運行多個程序了, CPU ?采用這種方式訪問內存,就需要段基址寄存器和段內偏移地址寄存器來存儲地址。

最終將兩個地址相加送上地址總線.而內存分段,相當于每個進程都會分配一個內存段,而且這個內存段需要是一塊連續的空間,主存里維護著多個內存段,當某個進程需要更多內存,并且超出物理內存的時候,就需要將某個不常用的內存段換到硬盤上,等有充足內存的時候在從硬盤加載進來,也就是 swap .每次交換都需要操作整個段的數據。

首先連續的地址空間是很寶貴的,例如一個 50M 的內存,在內存段之間有空隙的情況下,將無法支持 5 個需要 10M 內存才能運行的程序,如何才能讓段內地址不連續呢? 答案是內存分頁。

在保護模式下,每一個進程都有自己獨立的地址空間,所以段基地址是固定的,只需要給出段內偏移地址就可以了,而這個偏移地址稱為線性地址,線性地址是連續的,而內存分頁將連續的線性地址和和分頁后的物理地址相關聯,這樣邏輯上的連續線性地址可以對應不連續的物理地址.物理地址空間可以被多個進程共享。

而這個映射關系將通過頁表( page table)進行維護. 標準頁的尺寸一般為 4KB ,分頁后,物理內存被分成若干個 4KB 的數據頁,進程申請內存的時候,可以映射為多個 4KB 大小的物理內存,而應用程序讀取數據的時候會以頁為最小單位,當需要和硬盤發生交換的時候也是以頁為單位。

現代計算機多采用虛擬存儲技術,虛擬存儲讓每個進程以為自己獨占整個內存空間,其實這個虛擬空間是主存和磁盤的抽象,這樣的好處是,每個進程擁有一致的虛擬地址空間,簡化了內存管理,進程不需要和其他進程競爭內存空間,因為他是獨占的,也保護了各自進程不被其他進程破壞。

另外,他把主存看成磁盤的一個緩存,主存中僅保存活動的程序段和數據段,當主存中不存在數據的時候發生缺頁中斷,然后從磁盤加載進來,當物理內存不足的時候會發生 swap 到磁盤.頁表保存了虛擬地址和物理地址的映射,頁表是一個數組,每個元素為一個頁的映射關系,這個映射關系可能是和主存地址,也可能和磁盤,頁表存儲在主存,我們將存儲在高速緩沖區 cache ?中的頁表稱為快表 TLAB 。

  • 裝入位 表示對于頁是否在主存,如果地址頁每頁表示,數據還在磁盤

  • 存放位置 建立虛擬頁和物理頁的映射,用于地址轉換,如果為null表示是一個未分配頁

  • 修改位 用來存儲數據是否修改過

  • 權限位 用來控制是否有讀寫權限

  • 禁止緩存位 主要用來保證 cache 主存 磁盤的數據一致性

內存映射

正常情況下,我們讀取文件的流程為,先通過系統調用從磁盤讀取數據,存入操作系統的內核緩沖區,然后在從內核緩沖區拷貝到用戶空間,而內存映射,是將磁盤文件直接映射到用戶的虛擬存儲空間中,通過頁表維護虛擬地址到磁盤的映射,通過內存映射的方式讀取文件的好處有,因為減少了從內核緩沖區到用戶空間的拷貝,直接從磁盤讀取數據到內存,減少了系統調用的開銷,對用戶而言,仿佛直接操作的磁盤上的文件,另外由于使用了虛擬存儲,所以不需要連續的主存空間來存儲數據。

在 Java 中,我們使用 MappedByteBuffer 來實現內存映射,這是一個堆外內存,在映射完之后,并沒有立即占有物理內存,而是訪問數據頁的時候,先查頁表,發現還沒加載,發起缺頁異常,然后在從磁盤將數據加載進內存,所以一些對實時性要求很高的中間件,例如rocketmq,消息存儲在一個大小為1G的文件中,為了加快讀寫速度,會將這個文件映射到內存后,在每個頁寫一比特數據,這樣就可以把整個1G文件都加載進內存,在實際讀寫的時候就不會發生缺頁了,這個在rocketmq內部叫做文件預熱。

下面我們貼一段 rocketmq 消息存儲模塊的代碼,位于 MappedFile 類中,這個類是 rocketMq 消息存儲的核心類感興趣的可以自行研究,下面兩個方法一個是創建文件映射,一個是預熱文件,每預熱 1000 個數據頁,就讓出 CPU 權限。

????private?void?init(final?String?fileName,?final?int?fileSize)?throws?IOException?{this.fileName?=?fileName;this.fileSize?=?fileSize;this.file?=?new?File(fileName);this.fileFromOffset?=?Long.parseLong(this.file.getName());boolean?ok?=?false;ensureDirOK(this.file.getParent());try?{this.fileChannel?=?new?RandomAccessFile(this.file,?"rw").getChannel();this.mappedByteBuffer?=?this.fileChannel.map(MapMode.READ_WRITE,?0,?fileSize);TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(fileSize);TOTAL_MAPPED_FILES.incrementAndGet();ok?=?true;}?catch?(FileNotFoundException?e)?{log.error("create?file?channel?"?+?this.fileName?+?"?Failed.?",?e);throw?e;}?catch?(IOException?e)?{log.error("map?file?"?+?this.fileName?+?"?Failed.?",?e);throw?e;}?finally?{if?(!ok?&&?this.fileChannel?!=?null)?{this.fileChannel.close();}}}//文件預熱,OS_PAGE_SIZE?=?4kb?相當于每?4kb?就寫一個?byte?0?,將所有的頁都加載到內存,真正使用的時候就不會發生缺頁異常了public?void?warmMappedFile(FlushDiskType?type,?int?pages)?{long?beginTime?=?System.currentTimeMillis();ByteBuffer?byteBuffer?=?this.mappedByteBuffer.slice();int?flush?=?0;long?time?=?System.currentTimeMillis();for?(int?i?=?0,?j?=?0;?i?<?this.fileSize;?i?+=?MappedFile.OS_PAGE_SIZE,?j++)?{byteBuffer.put(i,?(byte)?0);//?force?flush?when?flush?disk?type?is?syncif?(type?==?FlushDiskType.SYNC_FLUSH)?{if?((i?/?OS_PAGE_SIZE)?-?(flush?/?OS_PAGE_SIZE)?>=?pages)?{flush?=?i;mappedByteBuffer.force();}}//?prevent?gcif?(j?%?1000?==?0)?{log.info("j={},?costTime={}",?j,?System.currentTimeMillis()?-?time);time?=?System.currentTimeMillis();try?{//?這里sleep(0),讓線程讓出?CPU?權限,供其他更高優先級的線程執行,此線程從運行中轉換為就緒Thread.sleep(0);}?catch?(InterruptedException?e)?{log.error("Interrupted",?e);}}}//?force?flush?when?prepare?load?finishedif?(type?==?FlushDiskType.SYNC_FLUSH)?{log.info("mapped?file?warm-up?done,?force?to?disk,?mappedFile={},?costTime={}",this.getFileName(),?System.currentTimeMillis()?-?beginTime);mappedByteBuffer.force();}log.info("mapped?file?warm-up?done.?mappedFile={},?costTime={}",?this.getFileName(),System.currentTimeMillis()?-?beginTime);this.mlock();}

JVM 中對象的內存布局

在linux中只要知道一個變量的起始地址就可以讀出這個變量的值,因為從這個起始地址起前8位記錄了變量的大小,也就是可以定位到結束地址,在 Java 中我們可以通過 Field.get(object) 的方式獲取變量的值,也就是反射,最終是通過 UnSafe 類來實現的.我們可以分析下具體代碼。

?Field?對象的?getInt方法??先安全檢查?,然后調用?FieldAccessor@CallerSensitivepublic?int?getInt(Object?obj)throws?IllegalArgumentException,?IllegalAccessException{if?(!override)?{if?(!Reflection.quickCheckMemberAccess(clazz,?modifiers))?{Class<?>?caller?=?Reflection.getCallerClass();checkAccess(caller,?clazz,?obj,?modifiers);}}return?getFieldAccessor(obj).getInt(obj);}獲取field在所在對象中的地址的偏移量?fieldoffsetUnsafeFieldAccessorImpl(Field?var1)?{this.field?=?var1;if(Modifier.isStatic(var1.getModifiers()))?{this.fieldOffset?=?unsafe.staticFieldOffset(var1);}?else?{this.fieldOffset?=?unsafe.objectFieldOffset(var1);}this.isFinal?=?Modifier.isFinal(var1.getModifiers());}UnsafeStaticIntegerFieldAccessorImpl?調用unsafe中的方法public?int?getInt(Object?var1)?throws?IllegalArgumentException?{return?unsafe.getInt(this.base,?this.fieldOffset);}

通過上面的代碼我們可以通過屬性相對對象起始地址的偏移量,來讀取和寫入屬性的值,這也是 Java 反射的原理,這種模式在jdk中很多場景都有用到,例如LockSupport.park中設置阻塞對象. 那么屬性的偏移量具體根據什么規則來確定的呢? 下面我們借此機會分析下 Java 對象的內存布局。

在 Java 虛擬機中,每個 Java 對象都有一個對象頭 (object header) ,由標記字段和類型指針構成,標記字段用來存儲對象的哈希碼, GC 信息, 持有的鎖信息,而類型指針指向該對象的類 Class ,在 64 位操作系統中,標記字段占有 64 位,而類型指針也占 64 位。

也就是說一個 ?Java ?對象在什么屬性都沒有的情況下要占有 16 字節的空間當前 JVM 中默認開啟了壓縮指針,這樣類型指針可以只占 32 位,所以對象頭占 12 字節, 壓縮指針可以作用于對象頭,以及引用類型的字段. JVM 為了內存對齊,會對字段進行重排序,這里的對齊主要指 ?Java ?虛擬機堆中的對象的起始地址為 8 的倍數,如果一個對象用不到 8N 個字節,那么剩下的就會被填充,另外子類繼承的屬性的偏移量和父類一致。

以 Long 為例,他只有一個非 static 屬性 value ,而盡管對象頭只占有 12 字節,而屬性 value 的偏移量只能是 16, 其中 4 字節只能浪費掉,所以字段重排就是為了避免內存浪費, 所以我們很難在 Java 字節碼被加載之前分析出這個 Java 對象占有的實際空間有多大,我們只能通過遞歸父類的所有屬性來預估對象大小,而真實占用的大小可以通過 ?Java agent 中的 Instrumentation獲取。

當然內存對齊另外一個原因是為了讓字段只出現在同一個 CPU 的緩存行中,如果字段不對齊,就有可能出現一個字段的一部分在緩存行 1 中,而剩下的一半在 緩存行 2 中,這樣該字段的讀取需要替換兩個緩存行,而字段的寫入會導致兩個緩存行上緩存的其他數據都無效,這樣會影響程序性能。

通過內存對齊可以避免一個字段同時存在兩個緩存行里的情況,但還是無法完全規避緩存偽共享的問題,也就是一個緩存行中存了多個變量,而這幾個變量在多核 CPU 并行的時候,會導致競爭緩存行的寫權限,當其中一個 CPU 寫入數據后,這個字段對應的緩存行將失效,導致這個緩存行的其他字段也失效。

在 Disruptor 中,通過填充幾個無意義的字段,讓對象的大小剛好在 64 字節,一個緩存行的大小為64字節,這樣這個緩存行就只會給這一個變量使用,從而避免緩存行偽共享,但是在 jdk7 中。

由于無效字段被清除導致該方法失效,只能通過繼承父類字段來避免填充字段被優化,而 jdk8 提供了注解@Contended 來標示這個變量或對象將獨享一個緩存行,使用這個注解必須在 JVM 啟動的時候加上 -XX:-RestrictContended 參數,其實也是用空間換取時間。

jdk6??---?32?位系統下public?final?static?class?VolatileLong{public?volatile?long?value?=?0L;public?long?p1,?p2,?p3,?p4,?p5,?p6;?//?填充字段}jdk7?通過繼承public?class?VolatileLongPadding?{public?volatile?long?p1,?p2,?p3,?p4,?p5,?p6;?//?填充字段}public?class?VolatileLong?extends?VolatileLongPadding?{public?volatile?long?value?=?0L;}jdk8?通過注解@Contendedpublic?class?VolatileLong?{public?volatile?long?value?=?0L;}

NPTL和 Java 的線程模型

按照教科書的定義,進程是資源管理的最小單位,而線程是 CPU 調度執行的最小單位,線程的出現是為了減少進程的上下文切換(線程的上下文切換比進程小很多),以及更好適配多核心 CPU 環境,例如一個進程下多個線程可以分別在不同的 CPU 上執行,而多線程的支持

既可以放在Linux內核實現,也可以在核外實現,如果放在核外,只需要完成運行棧的切換,調度開銷小,但是這種方式無法適應多 CPU 環境,底層的進程還是運行在一個 CPU 上,另外由于對用戶編程要求高,所以目前主流的操作系統都是在內核支持線程,而在Linux中

線程是一個輕量級進程,只是優化了線程調度的開銷.而在 JVM 中的線程和內核線程是一一對應的,線程的調度完全交給了內核,當調用Thread.run 的時候,就會通過系統調用 fork() 創建一個內核線程,這個方法會在用戶態和內核態之間進行切換,性能沒有在用戶態實現線程高

當然由于直接使用內核線程,所以能夠創建的最大線程數也受內核控制.目前 Linux上 的線程模型為 NPTL ( Native POSIX Thread Library),他使用一對一模式,兼容 POSIX 標準,沒有使用管理線程,可以更好地在多核 CPU 上運行.

線程的狀態

對進程而言,就三種狀態,就緒,運行,阻塞,而在 JVM 中,阻塞有四種類型,我們可以通過 jstack 生成 dump 文件查看線程的狀態.

  • BLOCKED (on object monitor) ?通過 synchronized(obj) 同步塊獲取鎖的時候,等待其他線程釋放對象鎖,dump 文件會顯示 waiting to lock <0x00000000e1c9f108>

  • TIMED WAITING (on object monitor) 和 WAITING (on object monitor) 在獲取鎖后,調用了 object.wait() 等待其他線程調用 object.notify(),兩者區別是是否帶超時時間

  • TIMED WAITING (sleeping) 程序調用了 thread.sleep(),這里如果 sleep(0) 不會進入阻塞狀態,會直接從運行轉換為就緒

  • TIMED WAITING (parking) 和 WAITING (parking) 程序調用了 Unsafe.park(),線程被掛起,等待某個條件發生,waiting on condition

而在 POSIX 標準中,thread_block 接受一個參數 stat ,這個參數也有三種類型,TASK_BLOCKED, TASK_WAITING, TASK_HANGING,而調度器只會對線程狀態為 READY 的線程執行調度,另外一點是線程的阻塞是線程自己操作的.

相當于是線程主動讓出 CPU 時間片,所以等線程被喚醒后,他的剩余時間片不會變,該線程只能在剩下的時間片運行,如果該時間片到期后線程還沒結束,該線程狀態會由 RUNNING 轉換為 READY ,等待調度器的下一次調度.

好了,關于線程就分析到這,關于 Java 并發包,核心都在 AQS 里,底層是通過 UnSafe類的 cas 方法,以及 park 方法實現,后面我們在找時間單獨分析,現在我們在看看 Linux 的進程同步方案.

POSIX表示可移植操作系統接口(Portable Operating System Interface of UNIX,縮寫為 POSIX ),POSIX標準定義了操作系統應該為應用程序提供的接口標準。

CAS 操作需要 CPU 支持,將比較 和 交換 作為一條指令來執行, CAS 一般有三個參數,內存位置,預期原值,新值 ,所以UnSafe 類中的 compareAndSwap 用屬性相對對象初始地址的偏移量,來定位內存位置.

線程的同步

線程同步出現的根本原因是訪問公共資源需要多個操作,而這多個操作的執行過程不具備原子性,被任務調度器分開了,而其他線程會破壞共享資源,所以需要在臨界區做線程的同步,這里我們先明確一個概念,就是臨界區,他是指多個任務訪問共享資源如內存或文件時候的指令,他是指令并不是受訪問的資源.

POSIX 定義了五種同步對象,互斥鎖,條件變量,自旋鎖,讀寫鎖,信號量,這些對象在 JVM 中也都有對應的實現,并沒有全部使用 POSIX 定義的 api,通過 Java 實現靈活性更高,也避免了調用native方法的性能開銷,當然底層最終都依賴于 pthread 的 互斥鎖 mutex 來實現,這是一個系統調用,開銷很大,所以 JVM 對鎖做了自動升降級,基于AQS的實現以后在分析,這里主要說一下關鍵字 synchronized .

當聲明 synchronized 的代碼塊時,編譯而成的字節碼會包含一個 monitorenter 和 多個 monitorexit (多個退出路徑,正常和異常情況),當執行 monitorenter 的時候會檢查目標鎖對象的計數器是否為0,如果為0則將鎖對象的持有線程設置為自己,然后計數器加1,獲取到鎖,如果不為0則檢查鎖對象的持有線程是不是自己,如果是自己就將計數器加1獲取鎖,如果不是則阻塞等待,退出的時候計數器減1,當減為0的時候清楚鎖對象的持有線程標記,可以看出 synchronized 是支持可重入的.

剛剛說到線程的阻塞是一個系統調用,開銷大,所以 JVM 設計了自適應自旋鎖,就是當沒有獲取到鎖的時候, CPU 回進入自旋狀態等待其他線程釋放鎖,自旋的時間主要看上次等待多長時間獲取的鎖,例如上次自旋5毫秒沒有獲取鎖,這次就6毫秒,自旋會導致 CPU 空跑,另一個副總用就是不公平的鎖機制,因為該線程自旋獲取到鎖,而其他正在阻塞的線程還在等待.除了自旋鎖, JVM 還通過 CAS 實現了輕量級鎖和偏向鎖來分別針對多個線程在不同時間訪問鎖和鎖僅會被一個線程使用的情況.后兩種鎖相當于并沒有調用底層的信號量實現(通過信號量來控制線程A釋放了鎖例如調用了 wait(),而線程B就可以獲取鎖,這個只有內核才能實現,后面兩種由于場景里沒有競爭所以也就不需要通過底層信號量控制),只是自己在用戶空間維護了鎖的持有關系,所以更高效.

如上圖所示,如果線程進入 monitorenter 會將自己放入該 objectmonitor 的 entryset隊列,然后阻塞,如果當前持有線程調用了 wait 方法,將會釋放鎖,然后將自己封裝成 objectwaiter 放入 objectmonitor 的 waitset 隊列,這時候 entryset 隊列里的某個線程將會競爭到鎖,并進入 active 狀態,如果這個線程調用了 notify 方法,將會把 waitset 的第一個 objectwaiter 拿出來放入 entryset (這個時候根據策略可能會先自旋),當調用 notify 的那個線程執行 moniterexit 釋放鎖的時候, entryset 里的線程就開始競爭鎖后進入 active 狀態.

為了讓應用程序免于數據競爭的干擾, Java ?內存模型中定義了 happen-before 來描述兩個操作的內存可見性,也就是 X 操作 happen-before 操作 Y , 那么 X 操作結果 對 Y 可見. JVM 中針對 volatile 以及 鎖 的實現有 happen-before 規則.

JVM 底層通過插入內存屏障來限制編譯器的重排序,以 volatile 為例,內存屏障將不允許 在 volatile 字段寫操作之前的語句被重排序到寫操作后面 , 也不允許讀取 volatile 字段之后的語句被重排序帶讀取語句之前.插入內存屏障的指令,會根據指令類型不同有不同的效果,例如在 monitorexit 釋放鎖后會強制刷新緩存.

而 volatile 對應的內存屏障會在每次寫入后強制刷新到主存,并且由于 volatile 字段的特性,編譯器無法將其分配到寄存器,所以每次都是從主存讀取,所以 volatile 適用于讀多寫少得場景,最好只有個線程寫多個線程讀,如果頻繁寫入導致不停刷新緩存會影響性能.

關于應用程序中設置多少線程數合適的問題,我們一般的做法是設置 CPU 最大核心數 * 2 ,我們編碼的時候可能不確定運行在什么樣的硬件環境中,可以通過 Runtime.getRuntime().availableProcessors() 獲取 CPU 核心,
但是具體設置多少線程數,主要和線程內運行的任務中的阻塞時間有關系,如果任務中全部是計算密集型,那么只需要設置 CPU 核心數的線程就可以達到 CPU 利用率最高,如果設置的太大,反而因為線程上下文切換影響性能,如果任務中有阻塞操作,而在阻塞的時間就可以讓 CPU 去執行其他線程里的任務.

我們可以通過 線程數量=內核數量 / (1 - 阻塞率)這個公式去計算最合適的線程數,阻塞率我們可以通過計算任務總的執行時間和阻塞的時間獲得,目前微服務架構下有大量的RPC調用,所以利用多線程可以大大提高執行效率,我們可以借助分布式鏈路監控來統計RPC調用所消耗的時間,而這部分時間就是任務中阻塞的時間,當然為了做到極致的效率最大,我們需要設置不同的值然后進行測試.

Java 中如何實現定時任務

定時器已經是現代軟件中不可缺少的一部分,例如每隔5秒去查詢一下狀態,是否有新郵件,實現一個鬧鐘等, Java ?中已經有現成的 api 供使用,但是如果你想設計更高效,更精準的定時器任務,就需要了解底層的硬件知識,比如實現一個分布式任務調度中間件,你可能要考慮到各個應用間時鐘同步的問題.

Java 中我們要實現定時任務,有兩種方式,一種通過 timer 類, 另外一種是 JUC 中的 ScheduledExecutorService ,不知道大家有沒有好奇 JVM 是如何實現定時任務的,難道一直輪詢時間,看是否時間到了,如果到了就調用對應的處理任務,但是這種一直輪詢不釋放 CPU 肯定是不可取的,要么就是線程阻塞,等到時間到了在來喚醒線程,那么 JVM 怎么知道時間到了,如何喚醒呢?

首先我們翻一下 JDK ,發現和時間相關的 API 大概有3處,而且這 3 處還都對時間的精度做了區分:

  • object.wait(long millisecond) ?參數是毫秒,必須大于等于 0 ,如果等于 0 ,就一直阻塞直到其他線程來喚醒 ,timer 類就是通過 wait() 方法來實現,下面我們看一下wait的另外一個方法

public?final?void?wait(long?timeout,?int?nanos)?throws?InterruptedException?{if?(timeout?<?0)?{throw?new?IllegalArgumentException("timeout?value?is?negative");}if?(nanos?<?0?||?nanos?>?999999)?{throw?new?IllegalArgumentException("nanosecond?timeout?value?out?of?range");}if?(nanos?>?0)?{timeout++;}wait(timeout);}

這個方法是想提供一個可以支持納秒級的超時時間,然而只是粗暴的加 1 毫秒.

  • Thread.sleep(long millisecond) 目前一般通過這種方式釋放 CPU ,如果參數為 0 ,表示釋放 CPU 給更高優先級的線程,自己從運行狀態轉換為可運行態等待 CPU 調度,他也提供了一個可以支持納秒級的方法實現,跟 wait 額區別是它通過 500000 來分隔是否要加 1 毫秒.

public?static?void?sleep(long?millis,?int?nanos)throws?InterruptedException?{if?(millis?<?0)?{throw?new?IllegalArgumentException("timeout?value?is?negative");}if?(nanos?<?0?||?nanos?>?999999)?{throw?new?IllegalArgumentException("nanosecond?timeout?value?out?of?range");}if?(nanos?>=?500000?||?(nanos?!=?0?&&?millis?==?0))?{millis++;}sleep(millis);}
  • LockSupport.park(long nans) ? Condition.await()調用的該方法, ScheduledExecutorService 用的 condition.await() 來實現阻塞一定的超時時間,其他帶超時參數的方法也都通過他來實現,目前大多定時器都是通過這個方法來實現的,該方法也提供了一個布爾值來確定時間的精度

  • System.currentTimeMillis() 以及 System.nanoTime() 這兩種方式都依賴于底層操作系統,前者是毫秒級,經測試 windows 平臺的頻率可能超過 10ms ,而后者是納秒級別,頻率在 100ns 左右,所以如果要獲取更精準的時間建議用后者

好了,api 了解完了,我們來看下定時器的底層是怎么實現的,現代PC機中有三種硬件時鐘的實現,他們都是通過晶體振動產生的方波信號輸入來完成時鐘信號同步的.

  • 實時時鐘 RTC ,用于長時間存放系統時間的設備,即使關機也可以依靠主板中的電池繼續計時. Linux 啟動的時候會從 RTC 中讀取時間和日期作為初始值,之后在運行期間通過其他計時器去維護系統時間

  • 可編程間隔定時器 PIT ,該計數器會有一個初始值,每過一個時鐘周期,該初始值會減1,當該初始值被減到0時,就通過導線向 CPU 發送一個時鐘中斷, CPU 就可以執行對應的中斷程序,也就是回調對應的任務

  • 時間戳計數器 TSC , 所有的 Intel8086 CPU 中都包含一個時間戳計數器對應的寄存器,該寄存器的值會在每次 CPU 收到一個時鐘周期的中斷信號后就會加 1 .他比 PIT 精度高,但是不能編程,只能讀取.

時鐘周期:硬件計時器在多長時間內產生時鐘脈沖,而時鐘周期頻率為1秒內產生時鐘脈沖的個數.目前通常為1193180.

時鐘滴答:當PIT中的初始值減到0的時候,就會產生一次時鐘中斷,這個初始值由編程的時候指定.

Linux啟動的時候,先通過 RTC 獲取初始時間,之后內核通過 PIT 中的定時器的時鐘滴答來維護日期,并且會定時將該日期寫入 RTC,而應用程序的定時器主要是通過設置 PIT 的初始值設置的,當初始值減到0的時候,就表示要執行回調函數了.

這里大家會不會有疑問,這樣同一時刻只能有一個定時器程序了,而我們在應用程序中,以及多個應用程序之間,肯定有好多定時器任務,其實我們可以參考 ?ScheduledExecutorService 的實現,只需要將這些定時任務按照時間做一個排序,越靠前待執行的任務放在前面,第一個任務到了在設置第二個任務相對當前時間的值,畢竟 CPU 同一時刻也只能運行一個任務,關于時間的精度問題,我們無法在軟件層面做的完全精準,畢竟 CPU 的調度不完全受用戶程序控制,當然更大的依賴是硬件的時鐘周期頻率,目前 TSC 可以提高更高的精度.

現在我們知道了, ?Java ?中的超時時間,是通過可編程間隔定時器設置一個初始值然后等待中斷信號實現的,精度上受硬件時鐘周期的影響,一般為毫秒級別,畢竟1納秒光速也只有3米,所以 JDK 中帶納秒參數的實現都是粗暴做法,預留著等待精度更高的定時器出現,而獲取當前時間 System.currentTimeMillis() 效率會更高,但他是毫秒級精度,他讀取的 Linux 內核維護的日期,而 System.nanoTime() ?會優先使用 TSC ,性能稍微低一點,但他是納秒級,Random 類為了防止沖突就用nanoTime生成種子.

Java 如何和外部設備通信

計算機的外部設備有鼠標、鍵盤、打印機、網卡等,通常我們將外部設備和和主存之間的信息傳遞稱為 I/O 操作 , 按操作特性可以分為,輸出型設備,輸入型設備,存儲設備.現代設備都采用通道方式和主存進行交互,通道是一個專門用來處理IO任務的設備.

CPU 在處理主程序時遇到I/O請求,啟動指定通道上選址的設備,一旦啟動成功,通道開始控制設備進行操作,而 CPU 可以繼續執行其他任務,I/O 操作完成后,通道發出 I/O 操作結束的中斷,處理器轉而處理 IO 結束后的事件.其他處理 IO 的方式,例如輪詢、中斷、DMA,在性能上都不見通道,這里就不介紹了.當然 ?Java ?程序和外部設備通信也是通過系統調用完成,這里也不在繼續深入了。

總結

以上是生活随笔為你收集整理的Java 和操作系统交互,你猜会发生什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

欧美日一级片 | 国产精品v a免费视频 | 亚洲在线看| 日韩av在线不卡 | 久久综合九色综合久99 | 91大神免费视频 | 免费观看视频黄 | 日韩最新中文字幕 | 亚洲在线免费视频 | 亚洲aⅴ乱码精品成人区 | 亚洲精品在线播放视频 | 国产九九九精品视频 | 天天拍天天干 | 伊人伊成久久人综合网小说 | 中文字幕黄色av | 国产精品3 | 国产精品免费视频观看 | 欧美成人猛片 | 天天干天天干天天干天天干天天干天天干 | 欧美久久久| 国产色中涩 | av免费在线观 | 亚洲激情国产精品 | 97av影院| 国产一区二区精品 | 在线成人免费电影 | 亚洲国产三级在线观看 | 国产精品一区久久久久 | 国产视频日韩视频欧美视频 | 高清不卡毛片 | 在线亚洲欧美日韩 | 五月婷婷丁香综合 | 欧美性另类| 69国产成人综合久久精品欧美 | 国产尤物在线观看 | 国产精品美女久久久久久久 | 在线观看911视频 | 热久久影视 | 成人久久综合 | 91麻豆精品国产91久久久无限制版 | 在线观看日本韩国电影 | 久久久亚洲影院 | 亚洲人成人在线 | 色视频网站免费观看 | 九九九九热精品免费视频点播观看 | 欧美一级在线 | 国内精品视频在线播放 | 国产一二区视频 | 国产免费一区二区三区最新 | 91丝袜美腿 | 五月婷婷综合激情网 | 成人黄色一级视频 | 国产一级久久久 | 精品国产成人在线影院 | 这里只有精彩视频 | 香蕉视频在线播放 | 最新av在线播放 | 国产精品久久久网站 | 91最新国产 | 国产三级视频 | 久久视频免费 | 欧美天天射| 九九精品视频在线看 | 免费看一级一片 | zzijzzij亚洲日本少妇熟睡 | 91精品电影 | 99热在线国产 | 亚洲精品五月 | 亚洲激情视频在线 | 亚洲精品国产麻豆 | 亚洲九九 | 欧美日韩在线第一页 | 久久人人爽人人爽人人 | 国产一区二区久久 | 亚洲精品国产精品国自产观看 | 免费在线一区二区三区 | 成人av一区二区兰花在线播放 | 亚洲视屏在线播放 | 五月婷婷中文字幕 | 中国一级片免费看 | 午夜 在线 | 中文字幕中文字幕在线一区 | 亚洲综合狠狠干 | 免费在线成人av电影 | 色噜噜在线观看视频 | 香蕉在线视频观看 | 精品999国产| 在线 你懂| 天堂网av 在线 | 色视频在线看 | 天天干夜夜| 国产 欧美 日产久久 | 国产日本亚洲 | 日韩欧美在线视频一区二区三区 | 国产午夜精品福利视频 | 六月色丁 | 不卡电影一区二区三区 | 亚洲艳情 | 在线视频 一区二区 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 国产最新91 | 午夜精品久久久久久久99 | 97综合视频| 久久综合之合合综合久久 | 久久久91精品国产一区二区精品 | 国产亚洲精品久久久久久 | wwwav视频| 久久乐九色婷婷综合色狠狠182 | av 一区二区三区四区 | 99视频精品全国免费 | 亚洲精品成人av在线 | 一区二区三区四区五区在线视频 | 黄色免费网站 | av大片网址 | 丁香网五月天 | 天天爱天天操 | 91视频在线免费看 | 日韩黄色软件 | 天天色天天操天天爽 | 1024手机在线看 | 免费在线观看不卡av | 特级西西www44高清大胆图片 | 国产精品久久久久毛片大屁完整版 | 免费黄色特级片 | 免费www视频| 国产精品久久久久久爽爽爽 | 九九视频精品免费 | 国产精品一区二区三区免费看 | 精品国产伦一区二区三区观看体验 | 五月婷婷欧美视频 | 91亚洲国产成人久久精品网站 | 欧美精品v国产精品v日韩精品 | 色狠狠一区二区 | 99国产精品久久久久老师 | 一本—道久久a久久精品蜜桃 | 国产九九热 | 亚洲人在线7777777精品 | 青草视频免费观看 | 午夜精品久久久久久久久久 | 久久久久观看 | 中文字幕色综合网 | av成人免费网站 | 成人欧美一区二区三区黑人麻豆 | 亚洲国产精品传媒在线观看 | 国产亚洲成人网 | 亚洲人成网站精品片在线观看 | 久久久国产一区二区 | 欧美一区二视频在线免费观看 | 少妇性色午夜淫片aaaze | 国产福利资源 | 欧美性护士 | 成人国产一区二区 | 国产男女无遮挡猛进猛出在线观看 | 久久久一本精品99久久精品 | 国产成人精品免高潮在线观看 | 国内精品久久久久影院优 | 91自拍视频在线观看 | 黄色小网站免费看 | 日韩一区二区三免费高清在线观看 | 日韩中文在线播放 | 蜜臀一区二区三区精品免费视频 | 人人插人人爱 | 国产成人三级 | 久久久伦理 | 91亚洲精品久久久蜜桃 | 久草电影在线观看 | 久久精品站 | 久久精品com| 精品电影一区 | 97香蕉久久国产在线观看 | 婷婷在线免费观看 | 特级西西www44高清大胆图片 | 国产精品毛片 | 456成人精品影院 | 黄色精品视频 | 中文字幕最新精品 | 中文资源在线官网 | 精品国产一区二区三区久久久蜜臀 | 亚洲狠狠婷婷综合久久久 | 日韩在线免费 | 永久免费的啪啪网站免费观看浪潮 | 色综合天天狠狠 | 国内精品久久久久久久影视简单 | 国产精品第一视频 | 久久精品xxx | 国产999精品久久久久久麻豆 | 色.com| 亚洲日日射 | 波多野结衣电影久久 | 国产精品v欧美精品 | 日本中文字幕在线看 | 久久电影色 | 色中色亚洲| 91av在线视频播放 | 亚洲毛片一区二区三区 | 国产一级h | 免费看片成年人 | 美女视频黄网站 | 日韩资源在线播放 | 91成人观看 | 亚洲精品高清在线观看 | 国产97免费| 日本精a在线观看 | 91在线最新 | 国产999精品 | 免费在线电影网址大全 | 亚洲乱码精品久久久 | 99精品一级欧美片免费播放 | 伊人精品在线 | 亚洲成av| 国产亚洲综合性久久久影院 | 在线电影av | 色欧美88888久久久久久影院 | 国产视频久 | 色老板在线视频 | 天天操狠狠操 | 亚洲在线不卡 | 亚洲网站在线看 | 国产成人三级在线观看 | 国产999久久久 | 黄色三级免费 | 国产五十路毛片 | 日日夜夜人人精品 | 久久久久福利视频 | 亚洲视频免费在线 | 开心激情网五月天 | 色吊丝在线永久观看最新版本 | 色狠狠综合天天综合综合 | 天天操狠狠操夜夜操 | 天天操天天干天天操天天干 | 91av蜜桃 | 天天综合网~永久入口 | 久久久福利 | 探花视频在线观看免费版 | 五月天免费网站 | 欧洲亚洲国产视频 | 日韩视频免费播放 | 成人免费观看视频大全 | 午夜久久久精品 | 国产黄av | 色天天中文 | 天堂av色婷婷一区二区三区 | 91在线资源| 日韩av一区二区三区四区 | av先锋中文字幕 | av电影久久| 国产精品久久久久久久久久东京 | 国产高清免费av | 91超碰在线播放 | 久久久网址 | 日韩区欧美久久久无人区 | 婷婷av色综合 | www.黄色片.com| 91探花国产综合在线精品 | 国产精品成人久久久久 | 国语对白少妇爽91 | 欧美日韩高清在线观看 | 国产日韩精品久久 | 国产成人性色生活片 | 香蕉视频色 | 91超级碰碰 | 国产91全国探花系列在线播放 | 国产福利免费看 | 99日韩精品 | 日韩美女免费线视频 | 亚洲国产成人在线 | 亚洲精品啊啊啊 | 久久伊99综合婷婷久久伊 | 9ⅰ精品久久久久久久久中文字幕 | www,黄视频 | 国产系列 在线观看 | 中文字幕频道 | 亚洲日本色| 草久在线视频 | 久久免费视频这里只有精品 | 日韩在线不卡视频 | 国产在线观看高清视频 | 一级免费黄视频 | h视频在线看| 久久久久久看片 | 色偷偷网站视频 | 久久一视频 | 激情综合五月婷婷 | 五月婷香 | 国产国语在线 | 久久综合99| 久久久鲁| 国产精品69久久久久 | 福利网址在线观看 | 国产精品一区免费看8c0m | 97综合在线 | 99久久久久久久久久 | 97国产 | 免费99精品国产自在在线 | 草久久av| 久久a v视频 | 亚洲成人资源在线 | 国产不卡视频在线播放 | 国产精品丝袜在线 | 久产久精国产品 | 亚洲 中文 欧美 日韩vr 在线 | 欧美性色综合 | 久久精品久久精品久久39 | 狠狠的操狠狠的干 | 久久精品福利视频 | 色黄视频免费观看 | 亚洲mv大片欧洲mv大片免费 | 亚州欧美视频 | 日本深夜福利视频 | 国产又粗又猛又爽 | 黄色aa久久 | 91亚洲在线观看 | 久久五月精品 | 成人四虎 | av手机在线播放 | 99视频黄| 天天射天天拍 | 国产精品不卡在线 | 色狠狠狠 | 久久精品电影 | 人人澡超碰碰97碰碰碰软件 | 在线观看国产日韩 | 999久久国精品免费观看网站 | 91在线视频免费91 | 91九色蝌蚪国产 | 五月婷婷在线综合 | www夜夜操| 久久伦理影院 | 色婷婷啪啪免费在线电影观看 | 日韩精品免费在线播放 | 五月婷婷婷婷婷 | 精品人人人人 | 久久综合九色综合久99 | 天天性天天草 | 黄色毛片大全 | 免费日韩 精品中文字幕视频在线 | 日韩欧美高清在线 | 91精品国自产在线观看 | 国产精品自产拍在线观看 | 亚洲欧美一区二区三区孕妇写真 | 伊人丁香| 狠狠干天天色 | 国产高清成人在线 | 日韩视频中文字幕在线观看 | 天天色草 | 色婷婷在线视频 | 亚洲国产成人久久 | 精品国产一区二区三区久久久蜜月 | 激情av网| 国产精品久久二区 | 干干干操操操 | 国产999精品久久久久久 | 国产看片免费 | av线上免费观看 | 日韩欧美精品在线视频 | 久久精品视频在线看 | 国产中文字幕在线视频 | 国产成人精品一区在线 | av大片免费看 | 亚洲精品一区二区久 | 国产中年夫妇高潮精品视频 | av免费在线观看网站 | 97色视频在线 | 亚洲精品人人 | 国产福利一区二区在线 | a v在线视频 | 精品亚洲网 | 亚洲国产成人在线播放 | 韩国av一区二区 | 麻豆传媒视频在线免费观看 | www.xxx.性狂虐 | 欧美日韩精品在线 | 韩国一区在线 | 狠狠狠干 | 99久久er热在这里只有精品15 | 成人免费观看网站 | 99久久久国产精品美女 | 国产主播大尺度精品福利免费 | 久久综合狠狠综合久久激情 | www.xxxx欧美| 97操操操 | 国精产品999国精产 久久久久 | 99在线免费视频观看 | 超碰97成人 | 337p欧美| 国产99久久九九精品免费 | 色香蕉视频 | 亚洲最新视频在线播放 | 中文字幕网站 | 日韩午夜一级片 | 在线观看久久久久久 | 中文字幕永久在线 | 久久av网| 亚洲精品在 | 久久综合婷婷国产二区高清 | 一二三精品视频 | 国产亚洲精品久久久久久网站 | 2018好看的中文在线观看 | 人人爽人人爽人人爽 | 九九热只有这里有精品 | 特级xxxxx欧美 | 欧美视频在线二区 | 9999精品 | 精品在线播放视频 | 亚洲精品视频在线看 | 中文字幕在线观看1 | 亚洲国内精品 | 国产精品福利无圣光在线一区 | 久久精品这里都是精品 | 最新日韩视频在线观看 | 国产免费一区二区三区网站免费 | 天天干天天操天天拍 | 日韩中文字幕a | 欧美日韩国产在线观看 | 国产精品乱码久久久久久1区2区 | 欧美日韩首页 | 男女激情麻豆 | 天天操狠狠操网站 | 久久成人午夜 | 日韩成人一级大片 | 天天天天天天天操 | 日韩有码中文字幕在线 | av电影在线免费观看 | 中文字幕第 | 国产区精品区 | 亚洲永久国产精品 | 色丁香久久 | 伊人狠狠色丁香婷婷综合 | 91人人爱 | 国产精品99爱| 欧美aa一级片 | 国产精品一区二区三区视频免费 | 久久开心激情 | 中文字幕xxxx | 国产第一页精品 | 国产精品二区三区 | 亚洲婷久久 | 国产精品视频大全 | 69国产盗摄一区二区三区五区 | 337p日本大胆噜噜噜噜 | 99精品视频在线观看播放 | 啪啪凸凸 | 久久国产精品影视 | 99久久久| av片在线观看免费 | 中文在线中文资源 | 美女黄久久 | 天天综合久久 | a黄在线观看 | 美腿丝袜一区二区三区 | 天天综合成人网 | 日产乱码一二三区别在线 | 精品国产亚洲一区二区麻豆 | 97视频人人免费看 | 丁香激情视频 | 日韩在线激情 | 狠狠色伊人亚洲综合网站野外 | 福利视频导航网址 | 青青啪| 色香蕉视频 | 午夜久久久久久久久久影院 | 国产精品久久久网站 | 国产视频日韩视频欧美视频 | 久久久这里有精品 | 国产在线播放不卡 | 九九九热精品免费视频观看 | 久久久免费在线观看 | 不卡的av中文字幕 | 少妇bbbb搡bbbb桶 | 欧美91精品久久久久国产性生爱 | 欧美午夜a| 国产视频一区二区在线观看 | 超碰在线cao| 久久躁日日躁aaaaxxxx | 在线亚洲观看 | 国产精品av电影 | 中文av网站| 久草视频中文在线 | 日本视频久久久 | 在线视频 你懂得 | 久久久免费精品 | 久草在线电影网 | 久久久影院官网 | 日韩av在线一区二区 | 在线免费观看欧美日韩 | 国产精品一区二区三区在线 | 一级成人免费视频 | 久久久电影网站 | 国产一级不卡视频 | 午夜婷婷在线播放 | 少妇高潮流白浆在线观看 | 国产男女爽爽爽免费视频 | 欧美日韩国产在线 | 国产一二三四在线观看视频 | 麻豆国产网站入口 | 久久99影院 | 中文字幕在线观 | 国产区在线视频 | 中文一区在线 | 免费看成人 | 中文字幕黄色 | 狠狠综合久久av | 欧美巨乳网 | 91污在线 | 一区 二区 精品 | 18性欧美xxxⅹ性满足 | 另类老妇性bbwbbw高清 | 91人网站 | 韩日电影在线观看 | 91精品国自产在线观看欧美 | 在线观看国产成人av片 | 色九色| 亚洲免费精品视频 | 国产1级毛片 | 日本精品中文字幕在线观看 | 国产精品国产三级国产aⅴ9色 | 精品国产一区二区三区在线 | 免费高清无人区完整版 | 99久久精品久久久久久动态片 | 91av精品| 欧美激情操| 欧美一区日韩精品 | 日韩伦理片hd | 日韩午夜在线 | 黄色软件在线观看免费 | 高清国产一区 | 激情在线免费视频 | 国产精品少妇 | 69av国产| 国产精品观看视频 | 久久久激情网 | 91麻豆传媒 | 黄色小网站在线观看 | 丁香导航| 国产成年免费视频 | 日韩成人在线免费观看 | 四虎精品成人免费网站 | 蜜桃av久久久亚洲精品 | 国产黄网站在线观看 | 久久精品电影院 | 中文字幕在线观看网 | 看黄色91| 成人免费毛片aaaaaa片 | 欧洲不卡av| 中文字幕第一页在线 | 999成人网 | 国产精品伦一区二区三区视频 | 中文字幕美女免费在线 | 日韩在线资源 | 国产免费黄色 | 中文字幕av在线免费 | 婷婷六月色 | 天天超碰| 国产精品欧美激情在线观看 | 欧美日韩在线视频观看 | 黄在线 | 久久免费视频在线观看 | 成年人在线观看免费视频 | 欧美一区二区三区激情视频 | 麻豆一级视频 | 水蜜桃亚洲一二三四在线 | 免费黄色在线网站 | 日韩av电影手机在线观看 | 国产久草在线观看 | 免费在线观看午夜视频 | 日日夜夜天天久久 | 天天综合日日夜夜 | 成人一区电影 | 国产免费黄色 | 国产经典av | 国产精品www | 日韩在线第一 | 激情五月在线观看 | 精品国产乱码久久久久久浪潮 | 午夜 免费 | 久久在线视频在线 | 亚洲国内精品在线 | 在线精品视频在线观看高清 | 国产成人一区二区精品非洲 | 久久在线免费观看视频 | 久久久官网 | av在线播放一区二区三区 | 视频直播国产精品 | 亚洲做受高潮欧美裸体 | 最近中文字幕免费视频 | 国产精品免费久久久久影院仙踪林 | 97超碰在线久草超碰在线观看 | 国产精品久久久久久久久久久久午夜 | 亚av在线 | 国产一级精品在线观看 | 999久久久欧美日韩黑人 | 懂色av一区二区在线播放 | 99热精品视 | 色综合久久五月天 | 免费视频二区 | 在线精品观看 | 精品久久国产精品 | 狠狠色狠狠色综合日日92 | 成人久久网| 午夜三级理论 | 开心色插 | 久久高清国产视频 | 99热精品国产一区二区在线观看 | 狠狠色2019综合网 | 91成年视频| 在线之家官网 | 福利视频午夜 | 天天爱综合 | 色先锋av资源中文字幕 | av最新资源 | 美女精品在线 | 久久国产精品色av免费看 | 香蕉视频色| 欧美精品生活片 | 国产xvideos免费视频播放 | 999热视频 | 在线视频 一区二区 | 久久99电影 | 久久久久综合 | 中文字幕 国产 一区 | 免费看一级一片 | 欧美在线观看视频一区二区三区 | 五月天激情在线 | 99精品国产免费久久 | 国产麻豆果冻传媒在线观看 | 国产91丝袜在线播放动漫 | 操操操av | 成人欧美在线 | 有码视频在线观看 | 欧美a级在线免费观看 | 成人免费看视频 | 东方av在 | 亚洲一区欧美精品 | 91av视频| 97人人添人澡人人爽超碰动图 | 成人h在线观看 | 久久久久国产精品一区二区 | av中文字幕第一页 | 成人午夜电影网 | 婷婷成人亚洲综合国产xv88 | 亚洲毛片视频 | 国内少妇自拍视频一区 | 国产一区二区久久精品 | 中中文字幕av在线 | 最近中文字幕久久 | 国产精品一区二区av影院萌芽 | 中文字幕av日韩 | 黄色片视频在线观看 | 91精品国产一区二区在线观看 | 99久久爱 | 蜜桃视频精品 | 久久综合狠狠狠色97 | 成 人 黄 色 视频免费播放 | 久久久久综合视频 | 韩日在线一区 | 色婷婷电影网 | 国产精品入口久久 | 久久久久久久精 | 久久久久国产一区二区三区四区 | 91黄色成人| 五月婷婷开心中文字幕 | 日韩欧美视频在线 | 日本中文字幕高清 | 黄色大片日本 | 国产91aaa | 国产成人精品久久久久 | 亚洲成av人片在线观看无 | 天天综合导航 | 久久综合九色综合97婷婷女人 | 成人网色| 久久精品国产一区二区电影 | 国产精品久久久亚洲 | 激情动态| 99电影456麻豆 | 日韩精品一区二区在线观看 | 99久久www | 区一区二区三在线观看 | 国产精品视频免费观看 | 欧美成人h版电影 | 久久只精品99品免费久23小说 | 久久伊人婷婷 | 四虎小视频 | 国产精品久久久久久久久久东京 | 国产精品久久久久久久久软件 | 韩日精品在线 | 97在线观看免费高清完整版在线观看 | 7777xxxx| 久久久亚洲国产精品麻豆综合天堂 | 亚洲精品乱码久久久久久 | 国产精品中文字幕在线播放 | 韩日精品视频 | 欧美一区二区日韩一区二区 | av中文字幕在线电影 | 九九涩涩av台湾日本热热 | 一区二区三区三区在线 | 欧美日韩性 | 欧美片网站yy | av一级久久 | 免费网站黄色 | 中文字幕在线观看的网站 | 狠狠的操狠狠的干 | 国产在线毛片 | 97视频在线播放 | 久草在线观 | av 在线观看 | 久久精品草| 四虎影视成人永久免费观看视频 | 伊人射 | 干干日日| 亚洲电影成人 | 欧美精品一区二区在线观看 | 97超碰人人澡人人爱学生 | 91精品国产91久久久久福利 | 高清一区二区三区av | 96看片 | 天天操偷偷干 | 欧美日韩超碰 | 成人黄色影片在线 | 国产永久免费高清在线观看视频 | 欧美性极品xxxx做受 | 亚洲专区视频在线观看 | 精品一区在线 | 天堂av官网 | www毛片com| 成人va在线观看 | 成人动态视频 | 国产原厂视频在线观看 | 黄色a在线| av线上看| 黄色毛片电影 | 草久久av| 特级西西www44高清大胆图片 | 国产午夜在线 | 蜜臀久久99静品久久久久久 | 国产精品岛国久久久久久久久红粉 | 国产精品亚洲人在线观看 | 亚洲精品免费视频 | av丝袜在线| 1024在线看片 | 丁香六月久久综合狠狠色 | 日本久久电影网 | 亚洲国产中文字幕 | 亚洲精品国产电影 | 婷婷视频 | www国产一区 | 二区精品视频 | 久久成人国产 | 天天色天天骑天天射 | 亚洲日韩欧美一区二区在线 | 五月婷婷视频 | 91中文字幕网 | 1024在线看片 | 69久久99精品久久久久婷婷 | 欧美亚洲国产精品久久高清浪潮 | 欧美黑人巨大xxxxx | 亚洲理论片在线观看 | 一区二区电影网 | 国产精品少妇 | 美女免费网视频 | 国产福利在线不卡 | 国产亚洲精品久久久久5区 成人h电影在线观看 | 激情丁香5月 | 国产五十路毛片 | 三级a毛片 | 日本精品视频在线观看 | 色婷婷精品大在线视频 | www.成人久久 | 久久久国产毛片 | 国产精品久久久久三级 | 丁香六月色| 精品国偷自产在线 | 久久激情五月激情 | 亚洲国产资源 | 99久久久久国产精品免费 | 久久日本视频 | 欧美在线观看视频一区二区 | 久久久夜色 | 国内精品视频在线 | 亚洲黄色在线观看 | 天堂激情网| 国产一二三四在线视频 | 四虎国产精品成人免费影视 | 日韩爱爱片 | 国产精品高潮呻吟久久久久 | 国产精品福利午夜在线观看 | 欧美成人精品欧美一级乱 | 视频在线99re | 片黄色毛片黄色毛片 | 精品在线视频播放 | 97在线观看 | 欧美三级高清 | 四虎在线免费视频 | 亚洲精品免费在线播放 | 久久久精选 | 天天天综合网 | 精品婷婷| 97视频网址 | 亚洲欧美综合精品久久成人 | 国产999精品久久久久久麻豆 | 日日夜夜天天综合 | 亚洲精品福利在线观看 | 亚洲热久久 | 香蕉视频在线视频 | 日韩精品免费在线 | 狠狠狠狠狠狠天天爱 | 国产一卡在线 | 天天操比 | 日韩高清一二区 | 99视频一区 | www.69xx| 天天操天天操天天操天天操天天操天天操 | 久久久久 | 久久伊人五月天 | 一区二区在线影院 | 久久久久久蜜av免费网站 | 天天射天天色天天干 | 国产一区二区免费在线观看 | 毛片永久免费 | 不卡在线一区 | 黄网站免费久久 | 国产高清专区 | 天天操天天操一操 | 在线免费观看视频一区二区三区 | 国产午夜精品免费一区二区三区视频 | 亚洲精品一区二区三区新线路 | 久久精品久久久久久久 | 在线免费观看一区二区三区 | 四虎永久免费在线观看 | 亚洲专区路线二 | 国产又粗又硬又爽的视频 | 激情www| 欧美在线视频一区二区三区 | 国产成人av福利 | 国产精品久久久久久久婷婷 | 国产网红在线观看 | 欧美精品成人在线 | 日韩免费电影网 | 在线久草视频 | 日日干美女 | 狠狠色狠狠色综合系列 | 亚洲码国产日韩欧美高潮在线播放 | 97视频在线观看播放 | 狠狠88综合久久久久综合网 | av一区二区三区在线播放 | 日韩国产欧美视频 | 手机看片| 成片免费 | 97视频亚洲 | 韩国一区视频 | 成人精品99 | 日韩av在线不卡 | 午夜精品福利一区二区三区蜜桃 | 在线观看91av | 四月婷婷在线观看 | 91香蕉国产在线观看软件 | 丁香婷婷久久 | 九九久 | 天天操天天是 | 成 人 黄 色 片 在线播放 | 国产一区免费视频 | 91电影福利 | 久久人人爽人人爽人人片av软件 | 91传媒免费在线观看 | 免费在线电影网址大全 | 狠狠干天天射 | 免费欧美精品 | 天天躁天天操 | 成人av在线影视 | 日本性久久 | 麻豆果冻剧传媒在线播放 | 免费的黄色av | 在线观看中文字幕第一页 | 毛片网免费 | 在线黄色免费 | 激情婷婷 | 久草在线播放视频 | 日韩免费一二三区 | 97成人精品视频在线观看 | 美女免费电影 | 91看片淫黄大片在线播放 | 久久久久久高潮国产精品视 | 黄色一级大片在线免费看国产一 | 日韩欧美一区二区三区黑寡妇 | 国产成人黄色网址 | 超碰免费公开 | 8x成人免费视频 | 婷婷天天色 | 国产精品热视频 | 久久经典国产 | 日日夜夜天天人人 | 国产淫片免费看 | 色操插| 狠狠干综合 | 欧美日韩国产精品一区二区三区 | 色狠狠操 | 伊人天堂av | 国产色视频一区二区三区qq号 | 香蕉网在线播放 | 最新av在线免费观看 | 午夜三级影院 | 久久香蕉国产精品麻豆粉嫩av | 日韩成人高清在线 | 国产永久网站 | 国产 一区二区三区 在线 | 免费美女久久99 | 欧美一级日韩免费不卡 | 18久久久久久 | 国产裸体视频网站 | 久久精品女人毛片国产 | 国产小视频在线免费观看视频 | 亚洲激情p | 97热在线观看 | 人人澡人人添人人爽一区二区 | 久久久久亚洲精品 | 婷婷日| 国产成人免费网站 | 欧美 亚洲 另类 激情 另类 | 国产中年夫妇高潮精品视频 | 在线a亚洲视频播放在线观看 | 国产 字幕 制服 中文 在线 | 国产一区在线播放 | 久久99热精品 | 91片网| 久久9视频 | 欧美日韩免费观看一区=区三区 | 亚洲精品免费视频 | 啪啪免费试看 | 99久久日韩精品视频免费在线观看 | 手机av电影在线 | 99精品视频免费在线观看 | 欧美午夜一区二区福利视频 | 精品 一区 在线 | 久久伊人免费视频 | 蜜臀av在线一区二区三区 | 欧美一级视频一区 | 在线 国产一区 | 久久免费的精品国产v∧ | 综合网av | 99在线观看视频 | 麻豆视传媒官网免费观看 | 亚洲成人网在线 | 亚洲免费一级电影 | 岛国大片免费视频 | 欧美aa在线 | 一区二区视 | 九九久久久久久久久激情 | 91亚洲国产成人久久精品网站 | 精品久久网 | 久草在线精品观看 | 中文字幕一区二区三区在线视频 | 亚洲国产中文字幕在线观看 | 五月婷香 | 国产成人黄色 | 天天做天天射 | 四虎永久免费网站 | 日韩精品中文字幕久久臀 | 色综合中文字幕 | 中文字幕免费播放 | 中文字幕乱码在线播放 | 一区二区三区日韩在线观看 | 国产精品入口a级 | 天天操天天操天天操天天操天天操 | 在线视频日韩一区 | 91久久精品一区二区三区 | 国产精品久久久久影视 | 天天操天天操天天操天天操 | 丁香激情综合 | h动漫中文字幕 | 一级片免费在线 | 久久99国产精品自在自在app | 天天操天天摸天天爽 | 日本在线观看中文字幕无线观看 | 五月婷婷视频在线 | 久久经典视频 | 国产在线观看二区 | 日日弄天天弄美女bbbb | 国产精品18久久久久久vr | av中文字幕在线免费观看 | 日韩午夜大片 | 中文字幕国产一区二区 | 在线观看黄网站 | 精品国产视频在线观看 | 91麻豆文化传媒在线观看 | 色婷婷亚洲婷婷 | 国内毛片毛片 | 亚洲精品在线二区 | 美女久久久久久久 | 日本乱码在线 | 精品国产伦一区二区三区 | www.午夜色.com | 五月激情丁香图片 | 96亚洲精品久久久蜜桃 | a'aaa级片在线观看 | 99久久精品国产一区二区三区 | 四虎在线永久免费观看 | 欧美激情一区不卡 | 国产精品第7页 | 日韩成人精品 |