1.認識JDK、JRE、JVM的關系
首先我們要區分JDK、JRE、JVM的關系
認清這個關系我們才能繼續理解JVM
- JDK(Java Development Kit)是一個開發工具包,是Java開發環境的核心組件,並且提供編譯、調試和運行一個Java程序所需要的所有工具,可執行文件和二進制文件,是一個平台特定的軟件
- JRE(Java Runtime Environment)是指Java運行時環境,是JVM的實現,提供了運行Java程序的平台。JRE包含了JVM,但是不包含Java編譯器/調試器之類的開發工具
- JVM(Java Virtual Machine)是指Java虛擬機,當我們運行一個程序時,JVM負責將字節碼轉換為特定機器代碼,JVM提供了內存管理/垃圾回收和安全機制等
區別與聯系:
- JDK是開發工具包,用來開發Java程序,而JRE是Java的運行時環境
- JDK和JRE中都包含了JVM
- JVM是Java編程的核心,獨立於硬件和操作系統,具有平台無關性,而這也是Java程序可以一次編寫,多處執行的原因
三者關系:
JDK包含JRE,JRE包含JVM。
然后我們需要知道的是Java語言的平台無關性是如何實現的
其實就是我們的JVM來保證的
- JVM屏蔽了操作系統和底層硬件的差異
- Java面向JVM編程,先編譯生成字節碼文件,然后交給JVM解釋成機器碼執行
- 通過規定基本數據類型的取值范圍和行為
2.JVM運行時數據區
首先我們來看JVM運行時數據區
首先簡單說一下各部分都是干什么的
方法區:方法區是一個線程之間共享的區域。常量,靜態變量以及JIT編譯后的代碼都在方法區。主要用於存儲已被虛擬機加載的類信息,也可以稱為“永久代”,垃圾回收效果一般,通過-XX:MaxPermSize控制上限。
堆內存:堆內存是垃圾回收的主要場所,也是線程之間共享的區域,主要用來存儲創建的對象實例,通過-Xmx 和-Xms 可以控制大小。
虛擬機棧(棧內存):棧內存中主要保存局部變量、基本數據類型變量以及堆內存中某個對象的引用變量。每個方法在執行的同時都會創建一個棧幀(Stack Frame)用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。棧中的棧幀隨着方法的進入和退出有條不紊的執行着出棧和入棧的操作。
程序計數器: 程序計數器是當前線程執行的字節碼的位置指示器。字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,是內存區域中唯一一個在虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
本地方法棧: 主要是為JVM提供使用native 方法的服務。
3. 測試
接下來我們來寫一段程序:

1 public class JVMTest { 2 public static void main(String[] args) { 3 JVMTest test=new JVMTest(); 4 int count = test.add(); 5 System.out.println(count); 6 } 7 public int add(){ 8 int a=1; 9 int b=2; 10 return a+b; 11 } 12 13 }
很簡單的一個程序我們就是來了解一下他怎么得到3的這個過程
在這個位置打上斷點,debug運行
可以看到我們的信息
主要因為我們執行了一個main線程
每個方法執行都會創建一個棧幀
這個就簡單說一下,接下來我們來到我們項目的目錄的target文件夾下,我們可以看到這個字節碼文件
點開看一看
我們可以利用javap這個指令對代碼進行一個反匯編
在當前目錄打開cmd窗口
我們可以看到一些提示信息
然后輸入javap -c JVMTest.class > app.txt
將他輸出到一個txt文件
其實這些都是JVM指令,有興趣可以自己去查一下
Compiled from "JVMTest.java" public class JVMTest { public JVMTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class JVMTest 3: dup 4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method add:()I 12: istore_2 13: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 16: iload_2 17: invokevirtual #6 // Method java/io/PrintStream.println:(I)V 20: return public int add(); Code: 0: iconst_1 1: istore_1 2: iconst_2 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: ireturn }
我就說一下add方法
大概就是這樣的如圖的一個過程
我大概講一下,你的add方法的棧幀中局部變量表存着你的局部變量,而操作數棧存着你每次操作的值,方法出口在我們的main棧幀里。
再來看看我們的main方法
而main棧幀中的操作數棧是test和result,而result不大一樣他是一個對象,是存在堆內存里的,這里會有一個引用指向堆。
這篇就說這些,如果有錯誤請及時更正