Java虛擬機必學之四大知識要點你掌握了嗎?

做爲一位 Java 程序員,在盡情享受 Java 虛擬機帶來好處的同時,咱們還應該去了解和思考「這些技術特性是如何實現的」,去了解最底層的原理。只有熟悉 JVM,你才能在遇到 OutOfMemory 等異常時,不會一籌莫展,不會一臉懵逼地上網找解決辦法,最後就算改了幾個啓動參數解決了問題,也仍是雲裏霧裏。程序員

此次,我提取了學習 Java 虛擬機的 X 大知識要點,助力你們深刻理解 JVM,知其然也知其因此然。 不過你在看知識點以前,最好能問問本身你會怎麼回答,再和我提供的內容作對比,這樣子提高會比較明顯。算法

第一大知識要點:Java 字節碼是如何在虛擬機裏運行的?緩存

我將以 HotSpot 虛擬機爲例,從虛擬機以及底層硬件兩個角度,來分享解析。安全

一、從虛擬機視角來看性能優化

執行 Java 代碼首先須要將它編譯而成的 class 文件加載到 Java 虛擬機中。加載後的 Java 類會被存放於方法區中。實際運行時,虛擬機會執行方法區內的代碼。架構

若是你熟悉 X86 的話,你會發現這和段式內存管理中的代碼段相似。並且,Java 虛擬機一樣也在內存中劃分出堆和棧來存儲運行時數據。不一樣的是,Java 虛擬機會將棧細分爲面向 Java 方法的 Java 方法棧,面向用 C++ 寫的 native 方法的本地方法棧,以及存放各個線程執行位置的 PC 寄存器。併發

 

在運行過程當中,每當調用進入一個 Java 方法,Java 虛擬機會在當前線程的 Java 方法棧中生成一個棧幀,用以存放局部變量以及字節碼的操做數。這個棧幀的大小是提早計算好的,並且 Java 虛擬機不要求棧幀在內存空間裏連續分佈。app

當退出當前執行的方法時,不論是正常返回仍是異常返回,Java 虛擬機均會彈出當前線程的當前棧幀,並將之捨棄。分佈式

二、從硬件視角來看微服務

Java 字節碼沒法直接執行。所以,Java 虛擬機須要將字節碼翻譯成機器碼。

在 HotSpot 裏面,上述翻譯過程有兩種形式:第一種是解釋執行,至關於同聲傳譯,即每解析一條字節碼,便翻譯成機器碼並執行;第二種是即時編譯(Just-In-Time compilation,JIT),則至關於線下翻譯,即將整個方法中所包含的字節碼統一翻譯成機器碼後在執行。

 

前者的優點在於無需等待編譯,然後者的優點在於實際運行速度更快。HotSpot 默認採用混合模式,綜合瞭解釋執行和即時編譯二者的優勢。它會先解釋執行字節碼,然後將其中反覆執行的熱點代碼,以方法爲單位進行即時編譯。

第二大知識要點:Java 虛擬機是如何加載 Java 類的?

Java 虛擬機加載 Java 類的過程可分爲加載、連接以及初始化三大步驟。

加載是指查找字節流,而且據此建立類的過程。加載須要藉助類加載器,在 Java 虛擬機中,類加載器使用了雙親委派模型,即接收到加載請求時,會先將請求轉發給父類加載器。

 

連接,是指將建立成的類合併至 Java 虛擬機中,使之可以執行的過程。連接還分驗證、準備和解析三個階段,分別完成「驗證被加載類是否知足 Java 虛擬機約束」,「爲被加載類靜態字段分配內存」,以及「將被加載類中的符號引用解析成爲實際引用」的工做。其中,Java 虛擬機規範並不要求解析階段必定要在連接步驟中完成。

初始化,則是爲標記爲常量值的字段賦值,以及執行 <clinit> 方法的過程。類的初始化僅會被執行一次,這個特性被用來實現單例的延遲初始化。

第三大知識要點:Java 虛擬機是如何進行垃圾回收的?

Java 虛擬機中的垃圾回收器採用可達性分析來探索全部存活的對象。它從一系列 GC Roots 出發,邊標記邊探索全部被引用的對象。爲了防止在標記過程當中堆棧的狀態發生改變,Java 虛擬機採起安全點機制來實現 Stop-The-World 操做,暫停其餘非垃圾回收線程。

回收垃圾對象的內存共有三種基礎算法,分別爲:會形成內存碎片的清除算法、性能開銷較大的壓縮算法、以及堆使用效率較低的複製算法。

一般來講,Java 虛擬機會採用分代回收的思想,將堆劃分爲新生代和老年代,而且經過在不一樣代中應用不一樣的垃圾回收算法。

傳統的作法是將新生代再劃分爲 Eden 區和兩個大小一致的 Survivor 區。在只針對新生代的 Minor GC 中,Eden 區和非空 Survivor 區的存活對象會被複制到空的 Survivor 區中,當 Survivor 區中的存活對象複製次數超過必定數值時,它將被晉升至老年代。

由於 Minor GC 只針對新生代進行垃圾回收,因此在枚舉 GC Roots 的時候,它須要考慮從老年代到新生代的引用。爲了不掃描整個老年代,Java 虛擬機引入了名爲卡表的技術,大體地標出可能存在老年代到新生代的引用的內存區域。

G1 垃圾回收器將堆劃分爲多個等大的區域,每一個區域均可以充當 Eden 區,Survivor 區或者老年代區。G1 會優先收集垃圾最多的區域,從而最大化垃圾回收的效益。這也是 Garbage First 名字的由來。

Java 11 中引入的實驗性垃圾回收器 ZGC,僅在掃描 GC Roots 時請求 Stop-The-World,暫停應用線程。所以,它宣稱可將 GC 暫停時間控制在 10ms 如下。ZGC 暫時沒有應用分代回收的思路,將整個堆空間當作一塊,其代價是垃圾回收 CPU 消耗較高。

第四大知識要點:Java 內存模型是什麼?

在現代計算機系統中,代碼一般不會按照書寫順序執行。形成這一狀況的緣由有三個,分別爲編譯器的重排序,處理器的亂序執行,以及內存系統的重排序。

之內存系統重排序爲例,在多處理器體系架構下,每一個處理器均可能緩存了一部分數據。因爲時刻保持緩存數據與內存數據同步的性能代價太大,所以部分體系架構可能容許緩存數據與內存數據不一樣步。這對 Java 程序的影響即是,兩個不一樣的 Java 線程在同一時間內看到的同一塊內存地址中的值可能不一樣。

Java 內存模型是針對上述問題而提出的一套規範,用以容許 Java 程序員更爲細緻地定義 Java 程序的內存行爲。它經過定義了一系列的 happens-before 操做,讓應用程序開發者可以輕易地表達不一樣線程的操做之間的內存可見性。

在遵照 Java 內存模型的前提下,即時編譯器以及底層體系架構可以調整內存訪問操做,以達到性能優化的效果。若是開發者沒有正確地利用 happens-before 規則,那麼將可能致使數據競爭。

順便在此給你們推薦一個Java架構方面的交流學習羣:698581634,裏面會分享一些資深架構師錄製的視頻資料:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化這些成爲架構師必備的知識體系,主要針對Java開發人員提高本身,突破瓶頸,相信你來學習,會有提高和收穫。在這個羣裏會有你須要的內容  朋友們請抓緊時間加入進來吧。

相關文章
相關標籤/搜索