細說JVM系列:JVM介紹
JVM是我們Javaer的最基本功底了,剛開始學Java的時候,一般都是從“Hello World”開始的,然後會寫個複雜點class,然後再找一些開源框架,比如Spring,Hibernate等等,再然後就開發企業級的應用,比如網站、企業內部應用、實時交易系統等等,直到某一天突然發現做的系統咋就這麼慢呢,而且時不時還來個記憶體溢位什麼的,今天是交易系統報了StackOverflowError,明天是網站系統報了個OutOfMemoryError,這種錯誤又很難重現,只有分析Javacore和dump檔案,運氣好點還能分析出個結果,執行遭的點,就直接去廟裡燒香吧!每天接客戶的電話都是戰戰兢兢的,生怕再出什麼么蛾子了。我想Java做的久一點的都有這樣的經歷,那這些問題的最終根結是在哪呢?——JVM。
一.JVM介紹
所謂虛擬機器,就是一臺虛擬的計算機,他是一款軟體,用來執行一系列虛擬計算機指令。大體上,虛擬機器可以分為系統虛擬機器和程式虛擬機器。大名鼎鼎的visual box、vmware就屬於系統虛擬機器,他們完全是對物理計算機的模擬,提供了一個可執行完整作業系統的軟體平臺。程式虛擬機器的代表就是java虛擬機器,他專門為執行單個計算機程式而設計,在java虛擬機器中執行的指令我們稱為java位元組碼指令。
JVM全稱是Java Virtual Machine,Java虛擬機器,也就是在計算機上再虛擬一個計算機,這和我們使用VMWare不一樣,那個虛擬的東西你是可以看到的,這個JVM你是看不到的,它存在記憶體中
JVM中我們最需要深入理解的就是它的儲存部分,儲存?硬碟?NO,NO,JVM是一個記憶體中的虛擬機器,那它的儲存就是記憶體了,我們寫的所有類、常量、變數、方法都在記憶體中,這決定著我們程式執行的是否健壯、是否高效,接下來的部分就是重點介紹之。
我們先把JVM這個虛擬機器畫出來,如下圖所示:
從這個圖可以看出,JVM是執行在作業系統之上的,它與硬體沒有直接的互動。
二.JVM組成部分
我們再來看下JVM有哪些組成部分,如下圖所示:
該圖參考了網上廣為流傳的JVM構成圖,大家看這個圖,整個JVM分為四部分:
1.ClassLoader類載入器
類載入器的作用是載入類檔案到記憶體,比如編寫一個HelloWord.java程式,然後通過javac編譯成class檔案,那怎麼才能載入到記憶體中被執行呢?Class Loader承擔的就是這個責任,那不可能隨便建立一個.class檔案就能被載入的,Class Loader載入的class檔案是有格式要求,在《JVM Specification》中式這樣定義Class檔案的結構:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
需要詳細瞭解的話,可以仔細閱讀《JVM Specification》的第四章“The class File Format”,這裡不再詳細說明。
友情提示:Class Loader只管載入,只要符合檔案結構就載入,至於說能不能執行,則不是它負責的,那是由Execution Engine負責的。
2.Execution Engine 執行引擎
執行引擎也叫做直譯器(Interpreter),負責解釋命令,提交作業系統執行。執行引擎是java虛擬機器的最核心元件之一,它負責執行虛擬機器的位元組碼。現代虛擬機器為了提高執行效率,會使用即時編譯技術將方法編譯成機器碼後再執行。
3.Native Interface本地介面
本地介面的作用是融合不同的程式語言為Java所用,它的初衷是融合C/C++程式,Java誕生的時候是C/C++橫行的時候,要想立足,必須有一個聰明的、睿智的呼叫C/C++程式,於是就在記憶體中專門開闢了一塊區域處理標記為native的程式碼,它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時載入native libraies。目前該方法使用的是越來越少了,除非是與硬體有關的應用,比如通過Java程式驅動印表機,或者Java系統管理生產裝置,在企業級應用中已經比較少見,因為現在的異構領域間的通訊很發達,比如可以使用Socket通訊,也可以使用Web Service等等,不多做介紹。
4.Runtime data area執行資料區
執行資料區是整個JVM的重點。我們所有寫的程式都被載入到這裡,之後才開始執行,Java生態系統如此的繁榮,得益於該區域的優良自治,下一章節詳細介紹之。
整個JVM框架由載入器載入檔案,然後執行器在記憶體中處理資料,需要與異構系統互動是可以通過本地介面進行,瞧,一個完整的系統誕生了!
三.JAVA虛擬機器規範
雖然java語言和java虛擬機器有著密切的聯絡,但兩者是完全不同的內容。java虛擬機器是一臺執行java位元組碼的虛擬計算機,它擁有獨立的執行機制,其執行的java位元組碼也未必由java語言編譯而成,像Groovy、Scala等語言生成的java位元組碼也可以由java虛擬機器執行。立足於java虛擬機器,可以產生各種各樣的跨平臺語言。除了語言特性各不相同外,他們可以共享java虛擬機器帶來的跨平臺性、優秀的垃圾回收器,以及可靠的即時編譯器。
因此,與java語言不通,java虛擬機器是一個高效的、效能優異的、商用級別的軟體執行和開發平臺。
java虛擬機器規範的主要內容大概有以下幾個部分:
- 定義了虛擬機器的內部結構
- 定義了虛擬機器執行的位元組碼型別和功能
- 定義了Class檔案的結構
- 定義了類的裝載、連線和初始化
四.JVM執行程式的過程
1) 載入.class檔案
2) 管理並分配記憶體
3) 執行垃圾收集
JRE(java執行時環境)由JVM構造的java程式的執行環,也是Java程式執行的環境,但是他同時一個作業系統的一個應用程式一個程序,因此他也有他自己的執行的生命週期,也有自己的程式碼和資料空間。JVM在整個jdk中處於最底層,負責於作業系統的互動,用來遮蔽作業系統環境,提供一個完整的Java執行環境,因此也就虛擬計算機。作業系統裝入JVM是通過jdk中Java.exe來完成,通過下面4步來完成JVM環境:
1) 建立JVM裝載環境和配置
2) 裝載JVM.dll
3) 初始化JVM.dll並掛界到JNIENV(JNI呼叫介面)例項
4) 呼叫JNIEnv例項裝載並處理class類。
五.JVM的生命週期
1) JVM例項對應了一個獨立執行的java程式它是程序級別
a) 啟動。啟動一個Java程式時,一個JVM例項就產生了,任何一個擁有public static void
main(String[] args)函式的class都可以作為JVM例項執行的起點
b) 執行。main()作為該程式初始執行緒的起點,任何其他執行緒均由該執行緒啟動。JVM內部有兩種執行緒:守護執行緒和非守護執行緒,main()屬於非守護執行緒,守護執行緒通常由JVM自己使用,java程式也可以表明自己建立的執行緒是守護執行緒
c) 消亡。當程式中的所有非守護執行緒都終止時,JVM才退出;若安全管理器允許,程式也可以使用Runtime類或者System.exit()來退出
2) JVM執行引擎例項則對應了屬於使用者執行程式的執行緒它是執行緒級別的
六.JRE/JDK/JVM是什麼關係?
JRE(JavaRuntimeEnvironment,Java執行環境),也就是Java平臺。所有的Java 程式都要在JRE下才能執行。普通使用者只需要執行已開發好的java程式,安裝JRE即可。
JDK(Java Development Kit)是程式開發者用來來編譯、除錯java程式用的開發工具包。JDK的工具也是Java程式,也需要JRE才能執行。為了保持JDK的獨立性和完整性,在JDK的安裝過程中,JRE也是 安裝的一部分。所以,在JDK的安裝目錄下有一個名為jre的目錄,用於存放JRE檔案。
JVM(JavaVirtualMachine,Java虛擬機器)是JRE的一部分。它是一個虛構出來的計算機,是通過在實際的計算機上模擬模擬各種計算機功能來實現的。JVM有自己完善的硬體架構,如處理器、堆疊、暫存器等,還具有相應的指令系統。Java語言最重要的特點就是跨平臺執行。使用JVM就是為了支援與作業系統無關,實現跨平臺。
七.細說JVM系列部落格預告
第二部分介紹了JVM的組成部分,以下內容也會圍繞部分二的圖示來解說JVM的各個組成部分。