'Java虛擬機底層原理和流程,看懂你就掌握60%JVM'

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

3、JVM內存管理及垃圾回收機制

JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

3、JVM內存管理及垃圾回收機制

JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(1)堆內存(heap)

所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。

操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語句才能正確的釋放本內存空間。但由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。這時由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,它不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊內存,雖然這種方法用起來最不方便,但是速度快,也是最靈活的。堆內存是向高地址擴展的數據結構,是不連續的內存區域。由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大

(2)棧內存(stack)

在Windows下, 棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是固定的(是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。 由系統自動分配,速度較快。但程序員是無法控制的。堆內存與棧內存需要說明:

基礎數據類型直接在棧空間分配,方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收。引用數據類型,需要用new來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量 。方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完成後從棧空間回收。局部變量new出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待GC回收。方法調用時傳入的literal參數,先在棧空間分配,在方法調用完成後從棧空間收回。字符串常量、static在DATA區域分配,this在堆空間分配。數組既在棧空間分配數組名稱,又在堆空間分配數組實際的大小。

如:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

3、JVM內存管理及垃圾回收機制

JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(1)堆內存(heap)

所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。

操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語句才能正確的釋放本內存空間。但由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。這時由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,它不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊內存,雖然這種方法用起來最不方便,但是速度快,也是最靈活的。堆內存是向高地址擴展的數據結構,是不連續的內存區域。由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大

(2)棧內存(stack)

在Windows下, 棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是固定的(是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。 由系統自動分配,速度較快。但程序員是無法控制的。堆內存與棧內存需要說明:

基礎數據類型直接在棧空間分配,方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收。引用數據類型,需要用new來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量 。方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完成後從棧空間回收。局部變量new出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待GC回收。方法調用時傳入的literal參數,先在棧空間分配,在方法調用完成後從棧空間收回。字符串常量、static在DATA區域分配,this在堆空間分配。數組既在棧空間分配數組名稱,又在堆空間分配數組實際的大小。

如:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(3)本地方法棧(java中的jni調用)

用於支持native方法的執行,存儲了每個native方法調用的狀態。對於本地方法接口,實現JVM並不要求一定要有它的支持,甚至可以完全沒有。Sun公司實現Java本地接口(JNI)是出於可移植性的考慮,當然我們也可以設計出其它的本地接口來代替Sun公司的JNI。但是這些設計與實現是比較複雜的事情,需要確保垃圾回收器不會將那些正在被本地方法調用的對象釋放掉。

(4)方法區(method)

它保存方法代碼(編譯後的java代碼)和符號表。存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值。

垃圾回收機制

堆裡聚集了所有由應用程序創建的對象,JVM也有對應的指令比如 new, newarray, anewarray和multianewarray,然並沒有向 C++ 的 delete,free 等釋放空間的指令,Java的所有釋放都由 GC 來做,GC除了做回收內存之外,另外一個重要的工作就是內存的壓縮,這個在其他的語言中也有類似的實現,相比 C++ 不僅好用,而且增加了安全性,當然她也有弊端,比如性能這個大問題。4、Java虛擬機的運行過程示例

上面對虛擬機的各個部分進行了比較詳細的說明,下面通過一個具體的例子來分析它的運行過程。

虛擬機通過調用某個指定類的方法main啟動,傳遞給main一個字符串數組參數,使指定的類被裝載,同時鏈接該類所使用的其它的類型,並且初始化它們。例如對於程序:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

3、JVM內存管理及垃圾回收機制

JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(1)堆內存(heap)

所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。

操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語句才能正確的釋放本內存空間。但由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。這時由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,它不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊內存,雖然這種方法用起來最不方便,但是速度快,也是最靈活的。堆內存是向高地址擴展的數據結構,是不連續的內存區域。由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大

(2)棧內存(stack)

在Windows下, 棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是固定的(是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。 由系統自動分配,速度較快。但程序員是無法控制的。堆內存與棧內存需要說明:

基礎數據類型直接在棧空間分配,方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收。引用數據類型,需要用new來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量 。方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完成後從棧空間回收。局部變量new出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待GC回收。方法調用時傳入的literal參數,先在棧空間分配,在方法調用完成後從棧空間收回。字符串常量、static在DATA區域分配,this在堆空間分配。數組既在棧空間分配數組名稱,又在堆空間分配數組實際的大小。

如:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(3)本地方法棧(java中的jni調用)

用於支持native方法的執行,存儲了每個native方法調用的狀態。對於本地方法接口,實現JVM並不要求一定要有它的支持,甚至可以完全沒有。Sun公司實現Java本地接口(JNI)是出於可移植性的考慮,當然我們也可以設計出其它的本地接口來代替Sun公司的JNI。但是這些設計與實現是比較複雜的事情,需要確保垃圾回收器不會將那些正在被本地方法調用的對象釋放掉。

(4)方法區(method)

它保存方法代碼(編譯後的java代碼)和符號表。存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值。

垃圾回收機制

堆裡聚集了所有由應用程序創建的對象,JVM也有對應的指令比如 new, newarray, anewarray和multianewarray,然並沒有向 C++ 的 delete,free 等釋放空間的指令,Java的所有釋放都由 GC 來做,GC除了做回收內存之外,另外一個重要的工作就是內存的壓縮,這個在其他的語言中也有類似的實現,相比 C++ 不僅好用,而且增加了安全性,當然她也有弊端,比如性能這個大問題。4、Java虛擬機的運行過程示例

上面對虛擬機的各個部分進行了比較詳細的說明,下面通過一個具體的例子來分析它的運行過程。

虛擬機通過調用某個指定類的方法main啟動,傳遞給main一個字符串數組參數,使指定的類被裝載,同時鏈接該類所使用的其它的類型,並且初始化它們。例如對於程序:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

編譯後在命令行模式下鍵入: java HelloApp run virtual machine

將通過調用HelloApp的方法main來啟動java虛擬機,傳遞給main一個包含三個字符串”run”、”virtual”、”machine”的數組。現在我們略述虛擬機在執行HelloApp時可能採取的步驟。

開始試圖執行類HelloApp的main方法,發現該類並沒有被裝載,也就是說虛擬機當前不包含該類的二進制代表,於是虛擬機使用ClassLoader試圖尋找這樣的二進制代表。如果這個進程失敗,則拋出一個異常。類被裝載後同時在main方法被調用之前,必須對類HelloApp與其它類型進行鏈接然後初始化。鏈接包含三個階段:檢驗,準備和解析。檢驗檢查被裝載的主類的符號和語義,準備則創建類或接口的靜態域以及把這些域初始化為標準的默認值,解析負責檢查主類對其它類或接口的符號引用,在這一步它是可選的。類的初始化是對類中聲明的靜態初始化函數和靜態域的初始化構造方法的執行。一個類在初始化之前它的父類必須被初始化。整個過程如下:

"

作為一名Java使用者,掌握JVM的體系結構也是必須的。

說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關係如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

運行期環境代表著Java平臺,開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

Java平臺由Java虛擬機和Java應用程序接口搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程序可以運行在這個平臺上。這個平臺的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

在Java平臺的結構中, 可以看出,Java虛擬機(JVM) 處在核心的位置,是程序與底層操作系統和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統, 其中依賴於平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統上實現;在JVM 的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運行而無需考慮底層平臺, 就是因為有Java虛擬機(JVM)實現了程序與操作系統的分離,從而實現了Java 的平臺無關性。

JVM在它的生存週期中有一個明確的任務,那就是運行Java程序,因此當Java程序啟動的時候,就產生JVM的一個實例;當程序運行結束的時候,該實例也跟著消失了。下面我們從JVM的體系結構和它的運行過程這兩個方面來對它進行比較深入的研究。

1、Java虛擬機的體系結構

·每個JVM都有兩種機制:

①類裝載子系統:裝載具有適合名稱的類或接口

②執行引擎:負責執行包含在已裝載的類或接口中的指令

·每個JVM都包含

方法區、Java堆、Java棧、本地方法棧、指令計數器及其他隱含寄存器

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

對於JVM的學習,在我看來這麼幾個部分最重要:

Java代碼編譯和執行的整個過程

JVM內存管理及垃圾回收機制

下面分別對這幾部分進行說明:

2、Java代碼編譯和執行的整個過程

也正如前面所說,Java代碼的編譯和執行的整個過程大概是:開發人員編寫Java代碼(.java文件),然後將之編譯成字節碼(.class文件),再然後字節碼被裝入內存,一旦字節碼進入虛擬機,它就會被解釋器解釋執行,或者是被即時代碼發生器有選擇的轉換成機器碼執行。

(1)Java代碼編譯是由Java源碼編譯器來完成,也就是Java代碼到JVM字節碼(.class文件)的過程。 流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(2)Java字節碼的執行是由JVM執行引擎來完成,流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

Java代碼編譯和執行的整個過程包含了以下三個重要的機制:

·Java源碼編譯機制

·類加載機制

·類執行機制

(1)Java源碼編譯機制

Java 源碼編譯由以下三個過程組成:

①分析和輸入到符號表

②註解處理

③語義分析和生成class文件

流程圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

最後生成的class文件由以下部分組成:

①結構信息:包括class文件格式版本號及各部分的數量與大小的信息

②元數據:對應於Java源碼中聲明與常量的信息。包含類/繼承的超類/實現的接口的聲明信息、域與方法聲明信息和常量池

③方法信息:對應Java源碼中語句和表達式對應的信息。包含字節碼、異常處理器表、求值棧與局部變量區大小、求值棧的類型記錄、調試符號信息

(2)類加載機制

JVM的類加載是通過ClassLoader及其子類來完成的,類的層次關係和加載順序可以由下圖來描述:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

①Bootstrap ClassLoader

負責加載$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類

②Extension ClassLoader

負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

③App ClassLoader

負責記載classpath中指定的jar包及目錄中class

④Custom ClassLoader

屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

(3)類執行機制

JVM是基於堆棧的虛擬機。JVM為每個新創建的線程都分配一個堆棧.也就是說,對於一個Java程序來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位保存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。

JVM執行class字節碼,線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應著每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。棧的結構如下圖所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

3、JVM內存管理及垃圾回收機制

JVM內存結構分為:方法區(method),棧內存(stack),堆內存(heap),本地方法棧(java中的jni調用),結構圖如下所示:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(1)堆內存(heap)

所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。

操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣代碼中的delete語句才能正確的釋放本內存空間。但由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。這時由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便。另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,它不是在堆,也不是在棧,而是直接在進程的地址空間中保留一塊內存,雖然這種方法用起來最不方便,但是速度快,也是最靈活的。堆內存是向高地址擴展的數據結構,是不連續的內存區域。由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大

(2)棧內存(stack)

在Windows下, 棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是固定的(是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。只要棧的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。 由系統自動分配,速度較快。但程序員是無法控制的。堆內存與棧內存需要說明:

基礎數據類型直接在棧空間分配,方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收。引用數據類型,需要用new來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量 。方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完成後從棧空間回收。局部變量new出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待GC回收。方法調用時傳入的literal參數,先在棧空間分配,在方法調用完成後從棧空間收回。字符串常量、static在DATA區域分配,this在堆空間分配。數組既在棧空間分配數組名稱,又在堆空間分配數組實際的大小。

如:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

(3)本地方法棧(java中的jni調用)

用於支持native方法的執行,存儲了每個native方法調用的狀態。對於本地方法接口,實現JVM並不要求一定要有它的支持,甚至可以完全沒有。Sun公司實現Java本地接口(JNI)是出於可移植性的考慮,當然我們也可以設計出其它的本地接口來代替Sun公司的JNI。但是這些設計與實現是比較複雜的事情,需要確保垃圾回收器不會將那些正在被本地方法調用的對象釋放掉。

(4)方法區(method)

它保存方法代碼(編譯後的java代碼)和符號表。存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值。

垃圾回收機制

堆裡聚集了所有由應用程序創建的對象,JVM也有對應的指令比如 new, newarray, anewarray和multianewarray,然並沒有向 C++ 的 delete,free 等釋放空間的指令,Java的所有釋放都由 GC 來做,GC除了做回收內存之外,另外一個重要的工作就是內存的壓縮,這個在其他的語言中也有類似的實現,相比 C++ 不僅好用,而且增加了安全性,當然她也有弊端,比如性能這個大問題。4、Java虛擬機的運行過程示例

上面對虛擬機的各個部分進行了比較詳細的說明,下面通過一個具體的例子來分析它的運行過程。

虛擬機通過調用某個指定類的方法main啟動,傳遞給main一個字符串數組參數,使指定的類被裝載,同時鏈接該類所使用的其它的類型,並且初始化它們。例如對於程序:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

編譯後在命令行模式下鍵入: java HelloApp run virtual machine

將通過調用HelloApp的方法main來啟動java虛擬機,傳遞給main一個包含三個字符串”run”、”virtual”、”machine”的數組。現在我們略述虛擬機在執行HelloApp時可能採取的步驟。

開始試圖執行類HelloApp的main方法,發現該類並沒有被裝載,也就是說虛擬機當前不包含該類的二進制代表,於是虛擬機使用ClassLoader試圖尋找這樣的二進制代表。如果這個進程失敗,則拋出一個異常。類被裝載後同時在main方法被調用之前,必須對類HelloApp與其它類型進行鏈接然後初始化。鏈接包含三個階段:檢驗,準備和解析。檢驗檢查被裝載的主類的符號和語義,準備則創建類或接口的靜態域以及把這些域初始化為標準的默認值,解析負責檢查主類對其它類或接口的符號引用,在這一步它是可選的。類的初始化是對類中聲明的靜態初始化函數和靜態域的初始化構造方法的執行。一個類在初始化之前它的父類必須被初始化。整個過程如下:

Java虛擬機底層原理和流程,看懂你就掌握60%JVM

"

相關推薦

推薦中...