JVM-Java虛擬機
JVM與Java體系結(jié)構(gòu)
TIOBE語言熱度排行榜
JVM通過JSR-292規(guī)范基本實現(xiàn)在Java虛擬機平臺上運行非Java語言編寫的程序。
虛擬機分為系統(tǒng)虛擬機(一個可以運行完整操作系統(tǒng)的軟件平臺)和程序虛擬機(專門為執(zhí)行單個計算機程序而設(shè)計)代表 JVM
JVM的特點
一次編譯,到處運行
自動內(nèi)存管理
自動垃圾回收功能
JVM代碼執(zhí)行流程(任一個環(huán)節(jié)失敗,都無法通過編譯)
Java源碼(.java文件)→Java編譯器→字節(jié)碼(.class)→JVM→操作系統(tǒng)
Java編譯器
詞法分析→語法分析→語法/抽象語法樹→語義分析→注解抽象語法樹→字節(jié)碼生成器
JVM
類加載器→字節(jié)碼效驗器→【翻譯字節(jié)碼(執(zhí)行解析)/JIT編譯器【保證性能】(編譯執(zhí)行)】執(zhí)行引擎
二次編譯
第一次是源文件編譯成字節(jié)碼文件
第二次是字節(jié)碼文件中的字節(jié)碼指令編譯成機器指令并緩存放入方法區(qū)中
JVM的架構(gòu)模型
Java編譯器輸入的指令流基本上是一種基于棧的指令集架構(gòu),另外一種是基于寄存器的指令集架構(gòu)。
由于跨平臺性的設(shè)計,Java的指令都是根據(jù)棧來設(shè)計的。優(yōu)點是跨平臺,指令集小,編譯器容易實現(xiàn);缺點是性能下降,實現(xiàn)同樣的功能需要更多的指令,執(zhí)行性能比寄存器差。
JVM的生命周期
虛擬機的啟動 是通過引導類加載器創(chuàng)建一個初始類來完成,這個類是由虛擬機的具體實現(xiàn)指定的。
虛擬機的執(zhí)行? 程序開始執(zhí)行它才運行,程序結(jié)束時結(jié)束。?
執(zhí)行一個所謂的Java程序的時候,真正在執(zhí)行的是一個叫做Java虛擬機的進程。
JVM發(fā)展歷史
Sun Classic VM 世界上第一款商用的Java虛擬機,jdk1.4時被淘汰。內(nèi)部只提供解釋器。?
Exact VM 準確式內(nèi)存管理。jdk1.2時,sun提供了此虛擬機,可以知道內(nèi)存中某個位置的數(shù)據(jù)具體是什么類型。Solaris平臺短暫使用,終被Hotspot虛擬機替換。
三大商用虛擬機
HotSpot VM 目前依舊在使用的虛擬機,jdk1.3以后都是默認虛擬機 ,HotSpot指的是特點代碼探測技術(shù);在服務(wù)器,桌面到移動端,嵌入式都有應(yīng)用。
通過計數(shù)器找到最具編譯價值代碼,出發(fā)即時編譯或棧上替換
通過編譯器(執(zhí)行性能)與解釋器(負責響應(yīng)時間)協(xié)同工作,在最優(yōu)化的程序響應(yīng)時間與最佳執(zhí)行性能中取得平衡
BEA的 JRockit 專注于服務(wù)器端應(yīng)用,不包含解釋器(不關(guān)注程序的啟動速度),全部代碼都靠即使編譯器編譯后執(zhí)行,世界上最快的JVM。
全面的Java運行時解決方案組合 -MissionControl服務(wù)套件(監(jiān)控內(nèi)存泄漏),是一套以極低的開銷來監(jiān)控丶管理和分析生產(chǎn)環(huán)境中的應(yīng)用程序的工具。
J9 市場定位于HotSpot接近,服務(wù)器端,桌面應(yīng)用,嵌入式等多用途
內(nèi)存結(jié)構(gòu)

類加載子系統(tǒng)
類加載子系統(tǒng)負責從文件系統(tǒng)或者網(wǎng)絡(luò)中加載Class文件,class文件在文件開頭有特定的文件標識。
ClassLoader只負責class文件的加載,至于是否可以運行,由Execution Engine(執(zhí)行引擎)決定。
加載的類信息存放于一塊稱為方法區(qū)的內(nèi)存空間。除了類的信息外,方法區(qū)中還會存放運行時常量池信息,可能還包括字符串字面量和數(shù)字常量。
類加載的過程
加載(狹義上)Loading
通過一個類的全限定名獲取定義此類的二進制字節(jié)流
將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)
在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口。
連接-linking
驗證(Verify) 目的在于確保class文件的字節(jié)流中包含信息符合當前虛擬機要求,保證被加載類的正確性,不會危害虛擬機自身安全;主要包括四種驗證:文件格式驗證,元數(shù)據(jù)驗證,字節(jié)碼驗證,符號引用驗證
準備(Prepre) 為類變量分配內(nèi)存并且設(shè)置該類變量的默認初始值,即零值。
這里不包含用final修飾的static,因為final在編譯的時候就會分配了,準備階段會顯示初始化。
這里不會為實例變量分配初始化,類變量會分配在方法區(qū)中,而實例變量是會鎖著對象一起分配到Java堆中。
解析(Resolve)
將常量池內(nèi)的符號引用轉(zhuǎn)換為直接引用的過程
解析操作往往會伴隨著JVM在執(zhí)行完初始化之后再執(zhí)行
符號引用就是一組符號來描述所引用的目標。符號引用的字面量形式明確定義在<Java虛擬機規(guī)范>的class文件格式中。直接引用就是直接指向目標的指針丶相對偏移量或一個簡潔定位到目標的句柄。
解析動作主要針對接口,字段,類方法,接口方法,方法類型等。
初始化
初始化階段就是執(zhí)行類構(gòu)造器方法<clinit>()的過程
此方法不需定義,是javac編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)代碼塊中的語句合并而來。
構(gòu)造器方法中指令按語句在源文件中出現(xiàn)的順序執(zhí)行。
<clinit>()不同于類的構(gòu)造器;虛擬機必須保證一個類的<clinit>()方法在多線程下被同步加鎖。
類加載器的分類
JVM支持兩種類型的類加載器,分別為引導類加載器(Bootstrap ClassLoader)和自定義類加載器(User-Defined ClassLoader).
一般來說,自定義類加載器就是程序員自己定義的類加載器,但是Java虛擬機規(guī)范是將所有派生于抽象類ClassLoader的類加載器都劃分為自定義類加載器。
無論類加載器的類型如何劃分,在程序中我們最常見的類加載器始終只有3個。
虛擬機自帶的加載器
啟動類加載器(引導類加載器,Bootstrap ClassLoader)
這個類加載使用C/C++語言實現(xiàn),嵌套在JVM內(nèi)部。
它用來加載Java的核心類庫(JAVA_HOME/jre/lib/rt.jar;resources.jar或sun.boot.class.path路徑下的內(nèi)容),用于提供JVM自身需要的類。
并不繼承自java.lang.ClassLoader,沒有父加載器。
加載擴展類和應(yīng)用程序類加載器,并指定為他們的父類加載器。
出于安全考慮,Bootstrap啟動類加載器只加載包名為java,javax,sun等開頭的類。
擴展類加載器(Extension ClassLoader)
Java語言編寫,由sun.misc.Lanucher$ExtClassLoader實現(xiàn)
派生于ClassLoader類
父類加載器為啟動類加載器
從java。ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫,或從JDK的安裝目錄的jre/lib/ext子目錄下加載類庫。如果用戶創(chuàng)建的JAR放在此目錄下,也會自動由擴展類加載器加載。
應(yīng)用程序類加載器(系統(tǒng)類加載器,AppClassLoader)-Java應(yīng)用程序的默認加載器
派生于ClassLoader類
父類加載器為擴展類加載器.
負責加載環(huán)境變量classpath或系統(tǒng)屬性
ClassLoader
ClassLoader類,是一個抽象類,其后所有的類加載器都繼承于它(除了引導類加載器Bootstrap ClassLoader)
雙親委派機制-工作原理
如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執(zhí)行;
如果父類加載器還存在其父加載器,則進一步向上委托,依次遞歸,請求最終將到達頂層的啟動類加載器;
如果父類加載器可以完成類加載任務(wù),就成功返回,倘若父類加載器無法完成此加載任務(wù),子加載器才會嘗試自己去加載,這就是雙親委派模式。
優(yōu)勢:①避免類的重復(fù)加載 ②保護程序安全,防止核心API被隨意篡改
沙箱安全機制 -對核心源代碼的保護(破壞引導類加載器,比如自創(chuàng)java.lang.String運行main方法)
其他
在JVM中表示兩個class對象是否為同一個類存在兩個必要條件:
類的完整類名必須一致,包括包名
加載這個類的ClassLoader(指ClassLoader實例對象)必須相同
類加載器的引用
JVM必須知道一個類是由那種具體的類加載器加載的。如果一個類型是由用戶類加載器加載的,那么JVM會將這個類加載器的一個引用作為類型信息的一部分保存在方法區(qū)中。
當解析一個類型到另一個類型的引用的時候,JVM需要保證這兩個類型的類加載器是相同的。
類的主動使用和被動使用
主動使用,分七種情況:
創(chuàng)建類的實例
訪問某個類或 接口的靜態(tài)變量,或者對該靜態(tài)變量賦值
調(diào)用類的靜態(tài)方法
反射
初始化一個類的子類
Java虛擬機啟動時被表明為啟動類的類
JDK7開始提供的動態(tài)語言支持
除了以上7種情況,其他使用Java類的方式都被看作是對類的被動使用,都不會導致類的初始化