java語言之所以有如此強大的生命力,與其對跨平臺使用的良好的支持有很大的關係。而這一平臺無關性依賴的正是java虛擬機。通常來講,高級語言的在不同的平臺遠行,通常需要編譯成不同的目標代碼。而採用java虛擬機,使java語言無需要重新編譯即可在不同的平臺上運行。java虛擬機只需要生成java虛擬機上運行的代碼,就可以在多種平臺上不加修改的直接運行。

java虛擬機始於一個main方法,main方法是java程序的起點,假使同一時間,有n個main方法正在運行,那麼就會有n個java虛擬機。main方法所被執行的線程是程序的初始線程,jvm當中的其他線程皆由main方法所啟動。java語言可以通過setDeamon方法來將某個線程設置為守護線程。只要當前jvm當中存在任何一個非守護線程沒有結束運行,當前jvm的守護線程就會全部工作,當最後一個僅有的用戶線程結束運行時,伴隨的守護線程才會結束運行。最具代表性的守護線程就是GC(垃圾回收)線程,如果沒有了用戶線程,守護線程也會因為沒有被守護的用戶線程而退出。

以下會嘗試以進程的角度來理解JVM。因為JVM其實也是一個運行在操作系統上的進程。當進程未運行時,只能理解為一個未啟動的程序。

以下我們比對下在linux環境下c語言和java語言運行一段測試程序時,程序的運行特點:

C語言運行一段代碼經歷的過程:

1) [guest@sit_ng_f_train ~]$ gcc Test.c -o Test

2) [guest@sit_ng_f_train ~]$ ./Test

JAVA語言運行一段代碼經歷的過程

1)[guest@sit_ng_f_train ~]$ javac Test.java

2) [guest@sit_ng_f_train ~]$ ls

會得到 Test.java Test.class 兩個文件。

3)[guest@sit_ng_f_train ~]$ java -classpath . Test

比對C和JAVA兩段測試程序 我們會發現,C語言的代碼運行直接運行了環境下的程序,而java必須通過java指令方可以運行,因為.class後綴結束的文件並不是操作系統可以識別的可執行的二進制文件,而我們通過java指令可以啟動進程,這裡體現了java運行語言的特點。以下我們深入理解下JVM在以上所處理的過程。

以上執行流程如下:java命令啟動了java虛擬機進程,虛擬機進程根據指令參數,讀取了一個名為Test的參數,把Test作為初始類加載到內存,然後從這個類的main方法開始執行。如何理解以上這段話呢?java程序的執行,首先得有虛擬機進程,而通過java指令,啟動了虛擬機進程,而Test.class文件也並不是直接在java虛擬機獲取了參數後,直接在內存上運行,而是被虛擬機的進程託管著運行。虛擬機進程準備就緒後,然後由類加載器加載Test.class文件和其他的一些類(包括String,Object等),然後以虛擬機執行引擎負責解釋Test.class中的字節碼指令,並負責把這些指令解釋成cpu能夠識別的指令,此後cpu才可以運行。

根據以上的理解,可以認為在執行一段Java程序時,實際運行的是java虛擬機進程,而不是我們所寫的Test類生成的Test.class文件。由java虛擬機實現了底層的一些處理,包括內存的分配和釋放。這裡java虛擬機與Test類的關係就好像是一個人與食物的關係,人通過接受食物參數,由虛擬機類加載引擎將食物加載到類執行引擎腸胃中,然後由類執行引擎負責消化食物,解析養份。消化完成後,再由類垃圾回收線程將食物廢料排出體外。綜上所述,java虛擬機實例的運行需要依賴三個子引擎來協作完成。

Java虛擬機淺談

java程序執行過程

當然,虛擬機所處理的細節遠遠不止如此,虛擬機運行過程中線程的執行,需要專門的內存空間來維護方法的調用,虛擬機加載的字節碼信息,也需要單獨的內存空間還存放,執行過程中還有對象的創建等等一系統的行為都是需要內存開銷的。後續的文章中我們將進行進一步的描述與講解。

綜上所述:

1.java虛擬機在操作系統層面只是一個進程。

2.java虛擬機這個進程由三個重要的引擎組成,三個引擎各司其職。類的加載引擎,類的執行引擎,類的垃圾回收引擎。

相關推薦

推薦中...