做者:鄭雨迪html
來源:極客時間《深刻拆解Java虛擬機》java
做爲一位Java程序員,在盡情享受Java虛擬機帶來好處的同時,咱們還應該去了解和思考「這些技術特性是如何實現的」,去了解最底層的原理。只有熟悉JVM,你才能在遇到 OutOfMemory等異常時,不會一籌莫展,不會一臉懵逼地上網找解決辦法,最後就算改了幾個啓動參數解決了問題,也仍是雲裏霧裏。git
此次,我會從我專欄裏提取了學習Java虛擬機的X大知識要點,助力你們深刻理解JVM,知其然也知其因此然。 不過你在看知識點以前,最好能問問本身你會怎麼回答,再和我提供的內容作對比,這樣子提高會比較明顯。
程序員
我將以HotSpot虛擬機爲例,從虛擬機以及底層硬件兩個角度,來分享解析。github
執行Java代碼首先須要將它編譯而成的class文件加載到Java虛擬機中。加載後的Java類會被存放於方法區中。實際運行時,虛擬機會執行方法區內的代碼。算法
若是你熟悉X86的話,你會發現這和段式內存管理中的代碼段相似。並且,Java虛擬機一樣也在內存中劃分出堆和棧來存儲運行時數據。不一樣的是,Java虛擬機會將棧細分爲面向Java方法的Java方法棧,面向用C++寫的native方法的本地方法棧,以及存放各個線程執行位置的PC寄存器。 緩存
在運行過程當中,每當調用進入一個Java方法,Java虛擬機會在當前線程的Java方法棧中生成一個棧幀,用以存放局部變量以及字節碼的操做數。這個棧幀的大小是提早計算好的,並且Java虛擬機不要求棧幀在內存空間裏連續分佈。安全
當退出當前執行的方法時,不論是正常返回仍是異常返回,Java虛擬機均會彈出當前線程的當前棧幀,並將之捨棄。性能優化
Java字節碼沒法直接執行。所以,Java虛擬機須要將字節碼翻譯成機器碼。微信
在HotSpot裏面,上述翻譯過程有兩種形式:第一種是解釋執行,至關於同聲傳譯,即每解析一條字節碼,便翻譯成機器碼並執行;第二種是即時編譯(Just-In-Time compilation,JIT),則至關於線下翻譯,即將整個方法中所包含的字節碼統一翻譯成機器碼後在執行。
前者的優點在於無需等待編譯,然後者的優點在於實際運行速度更快。HotSpot默認採用混合模式,綜合瞭解釋執行和即時編譯二者的優勢。它會先解釋執行字節碼,然後將其中反覆執行的熱點代碼,以方法爲單位進行即時編譯。
Java虛擬機加載Java類的過程可分爲加載、連接以及初始化三大步驟。
加載是指查找字節流,而且據此建立類的過程。加載須要藉助類加載器,在Java虛擬機中,類加載器使用了雙親委派模型,即接收到加載請求時,會先將請求轉發給父類加載器。
連接,是指將建立成的類合併至Java虛擬機中,使之可以執行的過程。連接還分驗證、準備和解析三個階段,分別完成「驗證被加載類是否知足Java虛擬機約束」,「爲被加載類靜態字段分配內存」,以及「將被加載類中的符號引用解析成爲實際引用」的工做。其中,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程序的內存行爲。它經過定義了一系列的happens-before操做,讓應用程序開發者可以輕易地表達不一樣線程的操做之間的內存可見性。
在遵照Java內存模型的前提下,即時編譯器以及底層體系架構可以調整內存訪問操做,以達到性能優化的效果。若是開發者沒有正確地利用happens-before規則,那麼將可能致使數據競爭。
Java內存模型是經過內存屏障來禁止重排序的。對於即時編譯器來講,內存屏障將限制它所能作的重排序優化。對於處理器來講,內存屏障會致使緩存的刷新操做。
個人專欄《深刻拆解Java虛擬機》已完結,很是感謝在我專欄完結以前的16000多名訂閱用戶,在未了解完整內容的狀況下,毅然訂閱了個人專欄。爲不辜負你們的信任,我幾乎每篇專欄都會大量閱讀HotSpot的源代碼,和同事討論實現背後的設計理念,在這個過程當中,我也發現了一些HotSpot中的Bug,或者年久失修的代碼,又或者是設計不合理的地方。這大概也可以算做寫專欄和我本職工做重疊的地方吧。
專欄雖然到此已經結束了,可是並不表明你對Java虛擬機學習的中止。我想,專欄的內容僅僅是爲你打開了JVM學習的大門,裏面的風景,仍是須要你本身來探索。在文章的後面,我列出了一系列的Java虛擬機技術的相關博客和閱讀資料,你仍然能夠繼續加餐。
你能夠關注國內幾位Java虛擬機大咖的微信公衆號:
R大,我的認爲是中文圈子裏最瞭解Java虛擬機設計實現的人,你能夠關注他的[知乎帳號](https://www.zhihu.com/people/rednaxelafx);
[你假笨](https://open.weixin.qq.com/qr/code?username=lovestblog),原阿里Java虛擬機團隊成員,現[PerfMa](http://www.perfma.com/) CEO;
[江南白衣](https://open.weixin.qq.com/qr/code?username=jnby1978),惟品會資深架構師;
[佔小狼](https://open.weixin.qq.com/qr/code?username=whywhy_zj),美團基礎架構部技術專家;
[楊曉峯](https://open.weixin.qq.com/qr/code?username=gh_9f3b2a4e2a74),前甲骨文首席工程師。
若是英文閱讀沒問題的話,你能夠關注[Cliff Click](http://cliffc.org/blog/)、[Aleksey Shipilv](https://shipilev.net/)(他的[JVM Anatomy Park](https://shipilev.net/jvm-anatomy-park/)十分有趣)和[Nitsan Wakart](http://psy-lob-saw.blogspot.com/)的博客。
你也能夠關注[Java Virtual Machine Language Submit](http://openjdk.java.net/projects/mlvm/jvmlangsummit/)和[Oracle Code One](https://www.oracle.com/code-one/index.html)(前身是JavaOne大會)中關於Java虛擬機的演講,以便掌握Java的最新發展動向。
固然,若是對GraalVM感興趣的話,你能夠訂閱咱們團隊的[博客](https://medium.com/graalvm)。以後我會考慮逐一進行翻譯。
至於其餘閱讀材料,你能夠參考R大的這份[書單](https://www.douban.com/doulist/2545443/),或者這個[彙總貼](https://github.com/deephacks/awesome-jvm)。
若是本專欄已經激發了你對Java虛擬機的學習熱情,那麼我建議你着手閱讀HotSpot源代碼,而且回饋OpenJDK開源社區。這種回饋並不必定是提交patch,也能夠是bug report或者改進建議等等。
道阻且長,努力加餐~!
能夠說,Java虛擬機就是每一位Java工程師進階加薪的利器,你想往上升,你想深刻技術,不想一直停留在簡單開發,或者你在作Java性能分析、調優工做時,那麼,Java虛擬機絕對是一把助力的利劍。
推薦個人完結專欄:《深刻拆解Java虛擬機》給你。