以下文章来源于Java情报局 ,作者大猿帅
?? 导读:“你是否也遇到过这些问题?
这段广告语写的好,趁着在家办公深入学习下JVM,先列出整体知识点
Java开发都知道JVM是Java虚拟机,上学时还用过的VM也叫虚拟机,先比较一波
所谓虚拟机(Virtual Machine),就是一台虚拟的计算机。它是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。
JVM
是 Java Virtual Machine
(Java虚拟机)的缩写,JVM
是一种用于计算设备的规范,它是一个虚构的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
Java虚拟机是二进制字节码的运行环境,负责装载字节码到其内部,解释/编译为对应平台的机器指令执行。每一条Java指令,Java虚拟机规范中都有详细定义,如怎么取操作数,怎么处理操作数,处理结果放在哪里。
我们平时所说的java字节码,指的是用java语言编写的字节码,准确的说任何能在jvm平台上执行的字节码格式都是一样的,所以应该统称为jvm字节码。
不同的编译器可以编译出相同的字节码文件,字节码文件也可以在不同的jvm上运行。
Java虚拟机与Java语言没有必然的联系,它只与特定的二进制文件格式——Class文件格式关联,Class文件中包含了Java虚拟机指令集(或者称为字节码、Bytecodes)和符号集,还有一些其他辅助信息。
JVM是运行在操作系统之上的,它与硬件没有直接的交互。
JDK
(Java Development Kit) 是 Java
语言的软件开发工具包(SDK
)。JDK
物理存在,是 Java Language
、Tools
、JRE
和 JVM
的一个集合。
Java编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令集架构则是基于寄存器的指令集架构。
两种架构之间的区别:
由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的,优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。
进入class文件所在目录,执行javap -v xx.class
反解析(或者通过IDEA插件Jclasslib
直接查看),可以看到当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等信息。
以上图中的 1+2 为例说明:
Classfile /Users/starfish/workspace/myCode/starfish-learning/starfish-learn/target/classes/priv/starfish/jvm/JVM1.class
Last modified 2020-2-7; size 487 bytes
MD5 checksum 1a9653128b55585b2745270d13b17aaf
Compiled from "JVM1.java"
public class priv.starfish.jvm.JVM1
SourceFile: "JVM1.java"
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#22 // java/lang/Object."<init>":()V
#2 = Class #23 // priv/starfish/jvm/JVM1
#3 = Class #24 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lpriv/starfish/jvm/JVM1;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 i
#16 = Utf8 I
#17 = Utf8 j
#18 = Utf8 k
#19 = Utf8 MethodParameters
#20 = Utf8 SourceFile
#21 = Utf8 JVM1.java
#22 = NameAndType #4:#5 // "<init>":()V
#23 = Utf8 priv/starfish/jvm/JVM1
#24 = Utf8 java/lang/Object
{
public priv.starfish.jvm.JVM1();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lpriv/starfish/jvm/JVM1;
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: iconst_1 //冒号前的数字表示程序计数器的数,常量1入栈
1: istore_1 //保存到1的操作数栈中,这里的1表示操作数栈的索引位置
2: iconst_2
3: istore_2
4: iload_1 //加载
5: iload_2
6: iadd //常量出栈,求和
7: istore_3 //存储到索引为3的操作数栈
8: return
LineNumberTable:
line 6: 0
line 7: 2
line 8: 4
line 9: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
2 7 1 i I
4 5 2 j I
8 1 3 k I
MethodParameters: length = 0x5
01 00 0D 00 00
}
Java虚拟机的启动是通过引导类加载器(Bootstrap Class Loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的。
有以下几种情况:
JNI Invocation API
来加载或卸载Java虚拟机时,Java虚拟机的退出情况《Java Language and Virtual Machine Specifications》:https://docs.oracle.com/javase/specs/index.html
JDK 版本升级不仅仅体现在语言和功能特性上,还包括了其编译和执行的 Java 虚拟机的升级。
虚拟机有很多,此外还有Azul VM、Liquid VM、Apache Harmony、TaobaoJVM、Graal VM等
《深入理解Java虚拟机》 《尚硅谷JVM》