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干貨資料:學習筆記與大廠面試題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM