通過 Windows 命令提示符(cmd)在桌面新建文件夾,并在該文件夾中編譯、運行一段 Java 程序段
566
2025-03-31
大家在平時的開發過程中是否遇到過StackOverflowError、OutOfMemoryError等類似的內存溢出錯誤呢?大家又是怎么解決這個問題的?再來,大家在面試過程中有沒有被面試官提問過jvm的內部構造及如何優化的奪命連環call呢?今天就讓我們來一探究竟,先從jvm的內部構造及原理說起,一步一步帶大家解決jvm的優化問題。
虛擬機(Virtual Machine,簡稱VM)就是一臺虛擬的計算機。它是一款軟件,用來執行一系列虛擬計算機指令。大體上,虛擬機可以分為系統虛擬機和程序虛擬機。
大名鼎鼎的visual box、vmware就屬于系統虛擬機,他們完全是對物理計算機的仿真,提供了一個可運行完整操作系統的軟件平臺。
程序虛擬機的代表就是Java虛擬機(jvm),他專門為執行單個計算機程序而設計,在Java虛擬機中執行的指令我們稱為java字節碼指令。
無論是系統虛擬機還是程序虛擬機,在上邊運行的軟件都被限制于虛擬機提供的資源中。虛擬機所在的位置:硬件的操作系統之上。虛擬機與JDK和JRE的關系如圖所示:
Java編譯器輸入的指令流基本上是一種基于棧的指令集架構,另一種指令集架構則是基于寄存器的指令集架構。那么他們之間有什么區別呢?
棧式架構特點:
設計和實現更簡單,適用于資源受限的系統;
避開了寄存器的分配難題,使用零地址指令方式分配;
指令流中的指令大部分是零地址指令,其執行過程依賴于操作棧。指令集更小,編譯器容易實現;
不需要硬件支持,可移植性好,更好實現跨平臺。
寄存器架構特點:
典型的應用是x86的二進制指令集:比如傳統的PC以及Android的Davlik虛擬機;
指令集架構則完全依賴于硬件,可移植性差;
性能優秀和執行更高效;
花費更小的指令去完成一項操作;
基于寄存器架構的指令集往往都以一地址指令、二地址指令和三地址指令為主。
機器指令是機器語言的一條語句,是一組有意義的二進制代碼,一條機器指令通常分為兩個部分:操作碼和地址碼。操作碼指出該指令應該執行什么樣的操作,代表了該指令的功能。地址碼指出該指令操作的對象,給出被操作對象的地址。零地址指令指機器指令中操作數地址的個數為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虛擬機進程終止;
線程調用Runtime類或者System類的exit方法,或者Runtime類的halt方法,并且java安全管理器也允許這次exit或halt操作;
JNI(Java Native Interface)規范描述了用JNI Invocation API來加載或卸載java虛擬機時,java虛擬機的退出情況。
如果說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 VM:J9是IBM開發的一個高度模塊化的JVM,在許多平臺上,IBM J9 VM都只能跟IBM產品一起使用。2017年IBM發布開源的OpenJ9,并貢獻給 Eclipse 基金會。
非主流JVM介紹:
Azul VM: 是Azul system 公司在Hot Spot基礎上進行的改進,是運行在其公司專有的硬件上,一個Azul VM 實例,都可以管理數十個CPU以及數百G的內存資源,而且通過巨大內存范圍內,實現可控的GC事件以及垃圾回收。
Graal VM: 是一個高性能的通用虛擬機,可以運行使用JavaScript,Python 3,Ruby,R,基于JVM的語言以及基于LLVM的語言開發的應用。GraalVM消除了編程語言之間的隔離性,并且通過共享運行時增強了他們的互操作性。它可以獨立運行,也可以運行在OpenJDK,Node.js,Oracle,MySQL等環境中。它的口號“Run Programs Faster Anywhere”。
如圖所示為HotSpot的架構簡圖,接下來我們會按照該圖的執行順序說一下JVM里邊的具體細節。
阿Q將持續更新java實戰方面的文章,感興趣的可以關注下,也可以來技術群討論問題呦!
Java JVM 虛擬化
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。