1. 程式人生 > >Java虛擬機(JVM)概述

Java虛擬機(JVM)概述

for hat 表現 歸納 req dash 每一個 類結構 添加

JVM(Java虛擬機)是一個抽象的計算模型。就如同一臺真實的機器,它有自己的指令集和執行引擎,可以在運行時操控內存區域。目的是為構建在其上運行的應用程序提供一個運行環境。JVM可以解讀指令代碼並與底層進行交互:包括操作系統平臺和執行指令並管理資源的硬件體系結構。本文主要對JVM進行概述,並介紹Java程序是如何在上面執行的。

虛擬機

從本質上講,虛擬機是個被構建來提供特定或通用目的服務環境的非實體計算機。這聽起來像是一個仿真器,用來仿真機器未配置或不能按要求執行任務的硬件組件。因此,我們要做的就是創建一個軟件,以軟件的形式模擬硬件提供的服務,使之看起來這個特定的硬件在系統中是實際存在的。虛擬機在一定程度上使用CPU虛擬化,為實際的硬件問題提供一個接口。所以可以說它實際上有兩種功能:提供一個虛擬的環境,或者將某些不存在的事物進行抽象化。但是當我們深入了解之後會發現,這兩種功能有著很明顯的不同。我們現在暫且不看它們之間的不同點,它們的共同點在於都“假裝”成它們不是的東西。正如Popek和Goldberg在論文“Formal Requirements for Virtualizable Third Generation Architectures”裏說的,它是“一個真實機器有效、獨立的復制品。”

基於不同的需求和用途,虛擬機有很多類型。一種叫完全虛擬化(full virtualization),這種虛擬機表現得像一臺真正的機器。其他類型的虛擬機會更精細,更專業,比如進程虛擬化(process virtualization)。而對JVM進行分類是很困難的,因為它對CPU進行了虛擬化,有自己的運行時環境、與底層平臺協調工作的內存管理器、垃圾收集器,當然還有大量作為中間字節碼輸入的類庫,最後但同樣重要的是,它能夠模擬機器的寄存器、堆棧等等。簡單地說,它是被Java編譯器編譯為java的本質——字節碼的遊樂場。字節碼實際上是JVM用來將代碼重新翻譯為本地機器指令所使用的機器代碼。

類文件格式

有趣的是,其實JVM並不關心Java語言或其他編程語言的語義和語法結構。當JVM執行一段程序的時候,它主要關註的是一種稱為“類文件”的特定文件格式。*.class類文件格式和Java代碼定義的面向對象的類結構毫無關系。編譯器將*.java文件編譯成*.class文件,然後JVM對*.class文件進行解譯,它不關心這個類文件是由哪種編譯器生成的,只要符合類文件的文件格式即可。Java編譯器將一段程序編譯為等價的類文件。這些類文件實際上包含了半編譯的代碼——字節碼。之所以稱之為半編譯,是因為字節碼並不像C/C++編譯器編譯的二進制文件一樣會被直接執行。字節碼要先被輸入到JVM中,然後再轉換為底層平臺可以執行的最終指令。所以字節碼包含了JVM的指令、符號表和其他的輔助信息。不管何種語言,能根據JVM的語法和結構約束編譯生成字節碼的編譯器,都是一個可以在JVM上執行的候選者。

JVM的定位

JVM將自身定位於字節碼和底層平臺之間。底層平臺是指操作系統(OS)和硬件。操作系統和硬件體系結構在不同的機器上可能不同,但是同一段Java程序可以不用做任何的代碼修改就能在不同的機器上運行。這是在虛擬環境中執行的程序語言的獨特之處。例如,由其他程序語言編譯器編譯的目標代碼如C++和Java相比的不同點在於,C++程序需要被特定平臺的編譯器重新編譯,從而使它能在不同的體系結構上面運行。而Java代碼並不需要做任何改變,因為由Java編譯器編譯的字節碼是在外圍的JVM上執行。因此,JVM負責重新解譯由Java編譯器生成的字節碼,並和底層平臺協調工作。也就是說,盡管Java編譯器生成的結果是平臺獨立的,但JVM與特定平臺相關的。除非兩臺機器有相同的體系結構,在某個體系結構上安裝和使用的JVM可能換一臺機器就不能正常工作了。

技術分享圖片

相對於JVM, JRE和JDK又是什麽?

想要運行Java程序,我們需要JVM因為它提供了字節碼的運行環境。Oracle提供了兩種不同的產品:JDK(Java開發工具)和JRE(Java運行環境)。JRE是我們安裝運行Java程序的最基本軟件。它和Java類庫以及運行Java程序所需要的其他組件一起夠成了JVM的一個實現。所以,如果我們想運行一個類文件或一段字節碼,僅需要JRE就夠了。而JDK(Java開發工具)是JRE的超集。它包含了JRE提供的所有東西,包括創建類文件的工具如Java編譯器、調試器和其他許多開發Java程序相關的工具。所以,當我們要創建類文件(編譯Java源碼)時,我們就需要JDK。下面是一張Java API文檔的截圖。註意組成JDK,JRE和Java SE API核心類庫的組件;通過這張截圖你可以了解JRE和JDK裏面都有哪些內容。

技術分享圖片

Java提供了Java虛擬機規範來讓我們對JVM的工作原理有一個完整的認識。你可以從這裏得到概念性知識,並開發一個自己的JVM;但這並不是一個簡單的工作。現在市場上已經有很多JVM了,其中有些是免費的,還有一些需要購買商業許可證才能使用。

在JVM上執行Java程序

每一個在JRE上運行的Java程序都會創建一個JVM實例。編譯後的Java類文件和其他被依賴的類文件會被加載到運行環境中。這一步由類加載器協助完成。

技術分享圖片

類加載器通過三步完成類加載。

Firstly, it loads the program classes, along with standard Java classes that are bundled with JDK in the form of bytecode. The standard classes form the core API library of Java. The bootstrap begins by locating the core API libraries classes typically situated in jre/lib.

首先,類加載器會以字節碼的形式加載程序類文件和與JDK綁定的標準Java類文件。標準類文件構成了Java API核心類庫。引導程序通過定位通常位於jre/lib目錄下的核心API類庫啟動。

然後,擴展機制定位擴展類庫,例如一些為開發或執行代碼而被添加到Java裏新的(可選)包。擴展類通常位於 jre/lib/ext目錄下。有時,擴展類會被放到系統屬性java.ext.dirs 定義的其他目錄下面。程序包使用JAR或ZIP的擴展名。

最後,如果要加載的類沒有在Java的標準類庫或擴展類庫中被找到,加載器會搜索CLASSPATH環境變量下定義的文件路徑,CLASSPATH裏面包含了諸多存儲類文件的地址。系統屬性java.class.path對CLASSPATH環境變量做了映射。

像JAR或ZIP這樣的歸檔文件都是包含了一些其他文件目錄的獨立文件,通常是壓縮文件格式。例如,程序中使用的標準類庫包含在歸檔文件 rt.jar中,該文件會和JDK被一同安裝。

一旦文件被定位並加載之後,類加載器會執行不同的功能,例如根據JVM的約束進行校驗、內存分配,或者在調用構造器設置定義的變量元素之前使用默認值初始化類變量。

當加載程序結束之後,字節碼指令被傳遞給執行引擎。然後JVM借助於綁定到指定平臺的特定JVM實現的本地代碼和底層操作系統進行交互。請註意,不同平臺的實現可能有略微不同。

數據存儲區的堆空間用於存儲動態或臨時分配的內存空間。類和數組是在這塊區域裏創建的。當創建對象大小超出堆內存空間時,垃圾收集器會回收內存。

Java棧,又叫棧幀,用於存儲局部變量和不同階段方法調用的臨時結果。每一次方法調用都會創建一個棧幀。

方法區基本上是JVM線程間的共享存儲區。

寄存器是一個模擬的底層機器寄存器,主要用於執行字節碼指令。PC寄存器或程序計數器是用於保存當前指令執行地址的主要寄存器。

JVM功能概述

JVM的功能可以歸納為:

  • 加載:通過類加載器加載類文件的過程。
  • 鏈接:鏈接類文件,提交給JVM在運行時執行。
  • 初始化:分配內存和調用類初始化方法設置變量值。

總結

使用虛擬機執行程序的最大好處是它是平臺獨立的。和C/C++這種高效的語言相比,這種類型編程語言的生產力可以彌補其性能上的弱點。本文僅僅是對JVM的一點淺見,但也許已經足以幫助理解JVM是如何實際工作的。

原文鏈接: developer 翻譯: ImportNew.com - 辰午
譯文鏈接: http://www.importnew.com/29224.html

Java虛擬機(JVM)概述