什麼是java虛擬機
我一般是能記例子就不記概念,不過概念還是要貼出來的
概念
Java虛擬機(Java Virtual Machine 簡稱JVM)是運行所有Java程序的抽象計算機,是Java語言的運行環境,它是Java 最具吸引力的特性之一。(copy的百度)
通俗易懂的理解
public class AA{
public static void main(String[] args) throws InterruptedException {
Thread.sleep(10000000);
}
}
首先寫一段代碼,然後cmd javac一下 然後用java AA啓動,win10的環境下可以看到
看到了我們熟悉的東西,其實這就是虛擬機的一個實例
jvm的生命週期
根據上面的例子應該很明顯就能知道生命週期的開始就是main開始運行的時候,但是並不是說main結束就是jvm生命週期的結束 做個試驗
public static void main(String[] args) {
new Thread(()-> {
System.out.println("sleep");
try {
Thread.sleep(1000000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} ).start();
System.out.println("main over");
}
還是上面的代碼把main方法改下 重新編譯 運行
main已經結束了 可是虛擬機還在
這是由於java的虛擬機種有兩種線程,一種叫叫守護線程,一種叫非守護線程,main函數就是個非守護線程,虛擬機的垃圾回收線程就是守護線程。
java的虛擬機中,只要有任何非守護線程還沒有結束,java虛擬機的實例都不會退出,所以即使main函數這個非守護線程退出,但是由於在main函數中啓動的匿名線程也是非守護線程,它還沒有結束,所以jvm沒辦法退出。
總結: java虛擬機的生命週期,當一個java應用main函數啓動時虛擬機也同時被啓動,而只有當在虛擬機實例中的所有非守護進程都結束時,java虛擬機實例才結束生命。
java虛擬機的體系結構
在 Java虛擬機規範中,一個虛擬機實例的行爲是分別按照子系統、內存區、數據類型和指令來描述的,這些組成部分一起展示了抽象的虛擬機的內部體系結構。
類裝載器子系統
類裝載器子系統負責查找並裝載類型信息。其實Java虛擬機有兩種類裝載器:系統裝載器和用戶自定義裝載器。前者是Java虛擬機實現的一部分,後者則是Java程序的一部分。
- 啓動類裝載器(bootstrap class loader):它用來加載 Java
的核心庫,是用原生代碼來實現的,並不繼承自java.lang.ClassLoader。 - 擴展類裝載器(extensions class loader):它用來加載 Java 的擴展庫。Java
虛擬機的實現會提供一個擴展庫目錄。該類加載器在此目錄裏面查找並加載 Java 類。 - 應用程序類裝載器(application class loader):它根據 Java 應用的類路徑(CLASSPATH)來加載 Java
類。一般來說,Java 應用的類都是由它來完成加載的。可以通過
ClassLoader.getSystemClassLoader()來獲取它。
除了系統提供的類裝載器以外,開發人員可以通過繼承 java.lang.ClassLoader類的方式實現自己的類裝載器,以滿足一些特殊的需求。
類裝載器子系統涉及Java虛擬機的其它幾個組成部分以及來自java.lang庫的類。ClassLoader定義的方法爲程序提供了訪問類裝載器機制的接口。此外,對於每一個被裝載的類型,Java虛擬機都會爲它創建一個java.lang.Class類的實例來代表該類型。和其它對象一樣,用戶自定義的類裝載器以及Class類的實例放在內存中的堆區,而裝載的類型信息則位於方法區。
類裝載器子系統除了要定位和導入二進制class文件外,還必須負責驗證被導入類的正確性,爲類變量分配並初始化內存,以及解析符號引用。這些動作還需要按照以下順序進行:
-
裝載(查找並裝載類型的二進制數據)
-
連接(執行驗證:確保被導入類型的正確性;準備:爲類變量分配內存,並將其初始化爲默認值;解析:把類型中的符號引用轉換爲直接引用)
-
初始化(類變量初始化爲正確初始值)
運行時數據區
這個放下一篇,連接:點我看內容
執行引擎
在Java虛擬機規範中,執行引擎的行爲使用指令集定義。實現執行引擎的設計者將決定如何執行字節碼,實現可以採取解釋、即時編譯或直接使用芯片上的指令執行,還可以是它們的混合。
執行引擎可以理解成一個抽象的規範、一個具體的實現或一個正在運行的實例。抽象規範使用指令集規定了執行引擎的行爲。具體實現可能使用多種不同的技術–包括軟件方面、硬件方面或樹種技術的結合。作爲運行時實例的執行引擎就是一個線程。
運行中Java程序的每一個線程都是一個獨立的虛擬機執行引擎的實例。從線程生命週期的開始到結束,它要麼在執行字節碼,要麼執行本地方法。
指令集
方法的字節碼流由Java虛擬機的指令序列構成。每一條指令包含一個單字節的操作碼,後面跟隨0個或多個操作數。操作碼錶示需要執行的操作;操作數向Java虛擬機提供執行操作碼需要的額外信息。當虛擬機執行一條指令時,可能使用當前常量池中的項、當前幀的局部變量中的值或者位於當前幀操作數棧頂端的值。
抽象的執行引擎每次執行一條字節碼指令。Java虛擬機中運行的程序的每個線程(執行引擎實例)都執行這個操作。執行引擎取得操作碼,如果操作碼有操作數,就取得它的操作數。它執行操作碼和跟隨的操作數規定的動作,然後再取得下一個操作碼。這個執行字節碼的過程在線程完成前將一直持續,通過從它的初始方法返回,或者沒有捕獲拋出的異常都可以標誌着線程的完成。
本地方法接口
Java本地接口,也叫JNI(Java Native Interface),是爲可移植性準備的。本地方法接口允許本地方法完成以下工作:
- 傳遞或返回數據
- 操作實例變量
- 操作類變量或調用類方法
- 操作數組
- 對堆的對象加鎖
- 裝載新的類
- 拋出異常
- 捕獲本地方法調用Java方法拋出的異常
- 捕獲虛擬機拋出的異步異常
- 指示垃圾收集器某個對象不再需要