zhouxihua0 2020-02-21
你是否也遇到过这些问题?
这段广告语写的好,趁着在家办公学习下JVM,先列出整体知识点
点赞+收藏 就学会系列,文章收录在 GitHub JavaEgg ,N线互联网开发必备技能兵器谱
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
JDK 版本升级不仅仅体现在语言和功能特性上,还包括了其编译和执行的 Java 虚拟机的升级。
虚拟机有很多,此外还有Azul VM、Liquid VM、Apache Harmony、TaobaoJVM、Graal VM等
《深入理解Java虚拟机》
《尚硅谷JVM》
程序的分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖程序计数器完成。Java堆是垃圾收集器管理的内存区域,因此也被称为“GC堆”。 3.指令流中大部分指令是零地址指令,执行过程依赖于栈操作。