本文是学习尚硅谷宋红康老师主讲的
尚硅谷JVM精讲与GC调优教程
的总结 ,部分内容也参考了 JavaGuide 网站(文末有链接)
JVM 概述
-
Oracle JDK 与 OpenJDK 是什么关系?
2006 年 SUN 公司将 Java 开源,也就有了 OpenJDK。2009 年 Oracle 收购了 Sun 公司,于是在 OpenJDK 的基础上搞了一个 Oracle JDK。
- OpenJDK 网站:https://openjdk.org/projects/jdk/ ,仓库地址:https://github.com/openjdk/jdk/。Oracle JDK 网站:https://www.oracle.com/java/technologies/downloads/。
- OpenJDK 是完全开源且免费的。Oracle JDK 不是完全开源的,会提供免费版本,但一般有时间限制。
- 功能性上两者基本一致。
- OpenJDK 根据 GPL v2 协议获得许可,Oracle JDK 使用 BCL/OTN 协议获得许可。
-
JDK、JRE、JVM 是什么关系?
JRE 包括 JVM 和 Java 基础类库,JDK 不仅包含 JRE,还包括编译器 javac 和其他工具,如 javadoc(文档生成器)、jdb(调试器)、jconsole(监控工具)、javap(反编译工具) 等。
不过,从 JDK 9 开始,就不需要区分 JDK 和 JRE 的关系了,取而代之的是模块系统和 jlink 工具。
-
常见的 JVM 有哪些?
HotSpot、JRockit、J9
-
JIT 是什么?
JIT 是 Just In Time 的缩写,JVM 将字节码文件转换为机器码时,JVM 类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。后面引进了 JIT 编译器,当 JIT 编译器完成第一次编译后,将字节码文件中的热点代码对应的机器码保存下来,下次可以直接使用。 -
JVM 架构图
字节码文件概述
-
生成 class 文件的编译器有哪些?
也叫前端编译器,有javac、ECJ(Eclipse Compiler for Java,是一种增量式编译器)、ajc(AspectJ编译器)。
-
javac 编译器的编译步骤有哪些?
词法分析、语法分析、语义分析、生成字节码。
-
如何解读 class 文件?
-
查看二进制工具:Notepad++ 安装 HEX-Editor 插件,或者 Binary Viewer软件。
-
使用 Oracle 官方的反解析工具 javap
javap -v xxx.class
-
使用IDEA插件:jclasslib 或 jclasslib bytecode viewer 客户端工具。
-
class 文件结构
-
class 文件结果有哪几部分?
- 魔鬼数字: 0xCAFEBABE
- class 文件版本
- 常量池
- 访问标识
- 类索引、父类索引、接口索引集合
- 字段表集合
- 方法表集合
- 属性表集合
官网文档:https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-4.html
-
JDK 1.1 对应的 class 文件版本是 45 ,后面版本依次加 1 。虚拟机JDK版本为1.k (k >= 2)时,对应的class文件格式版本号的范围为45 - 44 + k 。
-
常量池
常量池存放所有常量。常量池表项中,用于存放编译时期生成的各种
- 字面量
- 文本字符串
- 声明为 final 的常量值
- 符号引用
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
- 字面量
字节码指令
Java 虚拟机的指令由一个字节长度的操作码和操作数构成,指令集的操作码总数不超过 256 条。
官方文档: https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-6.html
JVM 中字节码的指令集按用途大致分为 9 类:
- 加载与存储指令,如 xload、xstore等
- 算术指令,如 iadd、isub 等
- 类型转换指令,如 i2l、l2f 等
- 对象的创建与访问指令,如 new、 getstatic、getfield 等
- 方法调用与返回指令,如 invokevirtual、ireturn 等
- 操作数栈管理指令,如 pop、dup 等
- 控制转移指令,如 ifeq、iflt 等
- 异常处理指令,如 athrow
- 同步控制指令,如 monitorenter、monitorexit
Java 虚拟机还有一个只在内部使用的基本类型:returnAddress ,Java 程序员不能使用这个类型,这个基本类型被用来实现 Java 程序中的 finally 子句。该类型是 jsr、ret 以及 jsr_w 指令需要使用到的,它的值是 JVM 指令的操作码指针。 returnAddress 类型不是简单意义的数值,不属于任何一种基本类型,并且它的值是不能被运行中的程序所修改的。
参考
- 尚硅谷JVM精讲与GC调优教程 (宋红康主讲) (https://www.bilibili.com/video/BV1Dz4y1A7FB?spm_id_from=333.788.videopod.episodes&vd_source=9266b9af652d5902d068c94b9d60116f)
M精讲与GC调优教程 (宋红康主讲) (https://www.bilibili.com/video/BV1Dz4y1A7FB?spm_id_from=333.788.videopod.episodes&vd_source=9266b9af652d5902d068c94b9d60116f) - JavaGuide网站 (https://javaguide.cn/java/basis/java-basic-questions-01.html)