1. 初識JVM
問題:我們的.java 文件是怎么運行的?
解答:我們的.java 文件通過編譯器編譯成.class 文件 ,通過我們的ClassLoader 加載器加載到JVM運行時內存塊。然后我們的CPU 去運行我們的程序。運行我們的程序是需要計算機里的很多模塊配合的,如CPU ,內存,寄存器 等。所以,不管是什么語言編寫的程序,只要最終編譯成.class 文件,那我們的java 虛擬機 就可以運行他,只要安裝了java 虛擬機,就可以在任何平臺上跑java 的程序,這也是java 強大的原因。以前塞班系統上的應用程序就是用我們的java 寫的。
問題:那我們的程序在虛擬機中又是怎么運行的呢?
解答:java虛擬機 也相當于我們的一個平臺,一個宿主。每一個應用在java 虛擬機中都是一個獨立的門戶。當我們的應用需要到的程序文件時就會通過我們的ClassLoader 把.class 文件加載到JVM運行時內存中。ClassLoader 怎么加載的我們后續再解釋。JVM 運行時內存大致可以分為五大類:方法區,堆區,虛擬機棧,本地方法棧,程序計數器。然而 我們的應用不可能都是一個線程,可能是多個線程。根據線程資源分配的話分為:線程共享區(方法區,堆區) 線程私有區(虛擬機棧,本地方法棧,程序計數器)。
現在我們分別來介紹一下這5個部分到底有什么作用,我們的程序在這5個功能模塊上是怎么協調運行我們的程序的。
- 程序計數器:從字面上的意思可理解成 運行程序的一個標記的東西。 我們的java程序是多線程的,CPU 可以在多個線程中分配時間片。當我們的某一個線程被掛起時,我們的程序計數器就要記錄當前代碼執行到了那一行,下一次線程被喚醒時,程序繼續從之前運行的那里開始運行。程序計數器的生命周期和線程是同步的。
- 虛擬機棧:說到棧,那就很明顯就是先進后出的。當我們運行某一個方法時就會創建一個棧幀,我們運行的方法 會在這個棧幀中去操作。棧幀中包括局部變量表,操作數棧,動態連接,返回地址等。正常我們的程序會編譯成字節碼指令,會在操作棧中入棧出棧 計算出每個方法的運行結果,然后返回,退出方法。
- 本地方法棧:本地方法棧和虛擬機棧大致相同,主要就是執行本地方法 native 方法。JNI開發過程中會用到本地方法棧。
- 堆:JVM 運行時內存管理的最大的一塊內存,該區域是存放我們對象實例,所以這塊的內存回收和創建 都是非常重要的,內存是有限的,如果管理不當就會導致內存不夠用,不夠用就會出現OOM 。
- 方法區:方法區主要存儲一些 加載的類的信息 版本號,字段,方法,接口 ,常量,靜態變量。