JVM集合之開篇點題

阿Q說程式碼 發表於 2021-06-10
JVM

大家在平時的開發過程中是否遇到過StackOverflowErrorOutOfMemoryError等類似的記憶體溢位錯誤呢?大家又是怎麼解決這個問題的?再來,大家在面試過程中有沒有被面試官提問過jvm的內部構造及如何優化的奪命連環call呢?今天就讓我們來一探究竟,先從jvm的內部構造及原理說起,一步一步帶大家解決jvm的優化問題。

虛擬機器簡介

虛擬機器(Virtual Machine,簡稱VM)就是一臺虛擬的計算機。它是一款軟體,用來執行一系列虛擬計算機指令。大體上,虛擬機器可以分為系統虛擬機器和程式虛擬機器。

  • 大名鼎鼎的visual boxvmware就屬於系統虛擬機器,他們完全是對物理計算機的模擬,提供了一個可執行完整作業系統的軟體平臺。
  • 程式虛擬機器的代表就是java虛擬機器(jvm),他專門為執行單個計算機程式而設計,在java虛擬機器中執行的指令我們稱為java位元組碼指令。

無論是系統虛擬機器還是程式虛擬機器,在上邊執行的軟體都被限制於虛擬機器提供的資源中。虛擬機器所在的位置:硬體的作業系統之上。虛擬機器與JDKJRE的關係如圖所示:
虛擬機器與和的關係

架構模型

Java編譯器輸入的指令流基本上是一種基於棧的指令集架構,另一種指令集架構則是基於暫存器的指令集架構。那麼他們之間有什麼區別呢?

棧式架構特點:

  • 設計和實現更簡單,適用於資源受限的系統;
  • 避開了暫存器的分配難題,使用零地址指令方式分配;
  • 指令流中的指令大部分是零地址指令,其執行過程依賴於操作棧。指令集更小,編譯器容易實現;
  • 不需要硬體支援,可移植性好,更好實現跨平臺。

暫存器架構特點:

  • 典型的應用是x86的二進位制指令集:比如傳統的PC以及AndroidDavlik虛擬機器;
  • 指令集架構則完全依賴於硬體,可移植性差;
  • 效能優秀和執行更高效;
  • 花費更小的指令去完成一項操作;
  • 基於暫存器架構的指令集往往都以一地址指令、二地址指令和三地址指令為主。

機器指令是機器語言的一條語句,是一組有意義的二進位制程式碼,一條機器指令通常分為兩個部分:操作碼和地址碼。操作碼指出該指令應該執行什麼樣的操作,代表了該指令的功能。地址碼指出該指令操作的物件,給出被操作物件的地址。零地址指令指機器指令中運算元地址的個數為0,一地址指令指機器指令中運算元地址的個數為1,以此類推。

由於跨平臺性的設計,java的指令都是根據棧來設計的,不同平臺的cpu架構不同,所以不能設計為基於暫存器的。

舉例:同樣執行2+3的邏輯操作,其指令分別如下:

基於棧的計算流程(以Java虛擬機器為例--idea中控制檯使用javap -v XXX.class執行)

 0: iconst_2  //常量2入棧
 1: istore_1  //將2從運算元棧儲存到區域性變數表 第1個位置
 2: iconst_3  //常量3入棧
 3: istore_2  //將2從運算元棧儲存到區域性變數表 第2個位置
 4: iload_1   //位置為1的資料壓入運算元棧
 5: iload_2   //位置為2的資料壓入運算元棧
 6: iadd      //常量2,3出棧,執行相加,並將結果壓入運算元棧頂
 7: istore_3  //結果5存到區域性變數表 第三個位置
 8: return    

基於暫存器的計算流程:

mov eax,2  //將eax暫存器的值設為1
add eax,3  //使eax暫存器的值加3
java虛擬機器的生命週期

虛擬機器的啟動:Java虛擬機器的啟動是通過引導類載入器建立一個初始類來完成的,這個類是由虛擬機器的具體實現指定的。

虛擬機器的執行:虛擬機器的任務是執行java程式,其真正執行的是一個叫做java虛擬機器的程式。

虛擬機器的退出:

  1. 程式正常執行結束;
  2. 程式在執行過程中遇到了異常或者錯誤而異常終止;
  3. 作業系統出現錯誤而導致java虛擬機器程式終止;
  4. 執行緒呼叫Runtime類或者System類的exit方法,或者Runtime類的halt方法,並且java安全管理器也允許這次exit或halt操作;
  5. JNI(Java Native Interface)規範描述了用JNI Invocation API來載入或解除安裝java虛擬機器時,java虛擬機器的退出情況。
常見的JVM

如果說java是跨平臺的語言,那jvm就是跨語言的平臺。只要是將該語言的檔案遵循jvm的規範編譯成jvm可以識別的位元組碼檔案,就可以在jvm上執行。jvm的特點:一次編譯,到處執行;自動記憶體管理;自動垃圾回收功能。

HotSpot、JRockit與J9並稱三大主流JVM:

HotSpot VM:從JDK1.3開始使用,到現在OpenJDK中也在使用。採用直譯器與即時編譯器並存的架構,擁有成熟的熱點程式碼探測技術和GC機制。所謂熱點探測技術有以下兩個方面的體現:一、通過計數器找到最具編譯價值的程式碼,觸發即時編譯或者棧上替換功能--機器指令(cpu可以直接執行的指令)本地快取;二、即時編譯器和直譯器協同工作,在最優化的程式響應時間與最佳執行效能之間平衡。

前端編譯器(javac或者Eclipse JDT中的增量式編譯器)把Java程式碼編譯成位元組碼,位元組碼是可以傳送給任何平臺並且能在那個平臺上執行的獨立於平臺的程式碼。

即時編譯器(JIT compiler,just-in-timecompiler)是一個把Java的位元組碼(包括需要被解釋的指令的程式)轉換成可以直接傳送給處理器(processor)的指令的程式。

JRockit VM:最初屬於BEA公司,2008年被Oracle收購。它專注於伺服器端應用,所以不太關注程式的啟動速度,裡邊不包含解析器,號稱是世界上最快的JVM。它提供的Mission Control服務套件,是一組以極低的開銷來監控、管理和分析生產環境中的應用程式的工具。它包括三個獨立的應用程式:記憶體洩漏監測器(Memory Leak Detector)、JVM執行時分析器(Runtime Analyzer)和管理控制檯(Management Console)。

J9 VMJ9IBM開發的一個高度模組化的JVM,在許多平臺上,IBM J9 VM都只能跟IBM產品一起使用。2017年IBM釋出開源的OpenJ9,並貢獻給 Eclipse 基金會。

非主流JVM介紹:

Azul VM: 是Azul system 公司在Hot Spot基礎上進行的改進,是執行在其公司專有的硬體上,一個Azul VM 例項,都可以管理數十個CPU以及數百G的記憶體資源,而且通過巨大記憶體範圍內,實現可控的GC事件以及垃圾回收。

Graal VM: 是一個高效能的通用虛擬機器,可以執行使用JavaScriptPython 3RubyR,基於JVM的語言以及基於LLVM的語言開發的應用。GraalVM消除了程式語言之間的隔離性,並且通過共享執行時增強了他們的互操作性。它可以獨立執行,也可以執行在OpenJDKNode.jsOracleMySQL等環境中。它的口號“Run Programs Faster Anywhere”。

HotSpot的整體架構圖

HotSpot的整體架構簡圖

如圖所示為HotSpot的架構簡圖,接下來我們會按照該圖的執行順序說一下JVM裡邊的具體細節,如果你有不同的意見或者更好的idea,歡迎聯絡阿Q:可以關注gzh“阿Q說程式碼”,也可以加阿Q好友qingqing-4132,阿Q期待你的到來!

後臺留言領取java乾貨資料:學習筆記與大廠面試題