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. 测试
接下来我们来写一段程序:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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不大一样他是一个对象,是存在堆内存里的,这里会有一个引用指向堆。
这篇就说这些,如果有错误请及时更正