第十九节:JVM 核心知识点总结
一、基本概念
1.1 OpenJDK
自 1996 年 JDK 1.0
发布以来,Sun 公司在大版本上发行了 JDK 1.1
、JDK 1.2
、JDK 1.3
、JDK 1.4
、JDK 5
,JDK 6
,这些版本的 JDK 都可以统称为 SunJDK 。
之后在 2006 年的 JavaOne 大会上,Sun 公司宣布将 Java 开源,在随后的一年多里,它陆续将 JDK 的各个部分在 GPL v2(GNU General Public License,version 2)协议下开源,并建立了 OpenJDK 组织来对这些代码进行独立的管理,这就是 OpenJDK 的来源,此时的 OpenJDK 拥有当时 sunJDK 7 的几乎全部代码。
1.2 OracleJDK
在 JDK 7 的开发期间,由于各种原因的影响,Sun 公司市值一路下跌,已无力推进 JDK 7 的开发,于是 JDK 7 的发布一直被推迟。
之后在 2009 年 Sun 公司被 Oracle 公司收购,为解决 JDK 7 长期跳票的问题,Oracle 将 JDK 7 中大部分未能完成的项目推迟到 JDK 8 ,并于 2011 年发布了JDK 7,在这之后由 Oracle 公司正常发行的 JDK 版本就由 SunJDK 改称为 Oracle JDK。
在 2017 年 JDK 9 发布后,Oracle 公司宣布:以后 JDK 将会在每年的 3 月和 9 月各发布一个大版本,即半年发行一个大版本,目的是为了避免众多功能被捆绑到一个 JDK 版本上而引发的无法交付的风险。
在 JDK 11 发布后,Oracle 同步调整了 JDK 的商业授权,宣布从 JDK 11 起,将以前的商业特性全部开源给 OpenJDK ,这样 OpenJDK 11 和 OracleJDK 11 的代码和功能,在本质上就完全相同了。
同时还宣布以后会发行两个版本的 JDK :
- 一个是在 GPLv2 + CE 协议下由 Oracle 开源的 OpenJDK;
- 一个是在 OTN 协议下正常发行的 OracleJDK。
两者共享大部分源码,在功能上几乎一致。唯一的区别是 Oracle OpenJDK 可以在开发、测试或者生产环境中使用,但只有半年的更新支持;而 OracleJDK 对个人免费,但在生产环境中商用收费,可以有三年时间的更新支持。
目前最新的长期支持的 JDK 是 JDK 21(LTS),详情可以参考朋友 why 技术的帖子。
1.3 HotSpot VM
它是 Sun/Oracle JDK 和 OpenJDK 中默认的虚拟机,也是目前使用最为广泛的虚拟机。
最初由 Longview Technologies 公司设计发明,该公司在 1997 年被 Sun 公司收购,随后 Sun 公司在 2006 年开源 SunJDK 时也将 HotSpot 虚拟机一并进行了开源。
Oracle 收购 Sun 以后,建立了 HotRockit 项目,并将其收购的另外一家公司(BEA)的 JRockit 虚拟机中的优秀特性集成到 HotSpot 中。
HotSpot 在这个过程里移除掉永久代,并吸收了 JRockit 的 Java Mission Control 监控工具等功能。
到 JDK 8 发行时,采用的就是集两者之长的 HotSpot VM。
我们可以在自己的电脑上使用 java -version
来获得 JDK 的信息:
二、Java 内存区域
Java 内存区域我们之前讲过,这里再盘一盘。
2.1 程序计数器
程序计数器(Program Counter Register)是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。
字节码解释器通过改变程序计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要该计数器来完成。
每个线程都拥有一个独立的程序计数器,各个线程之间的计数器互不影响,独立存储。
2.2 虚拟机栈
虚拟机栈(Java Virtual Machine Stack)也是线程私有,它描述的是 Java 方法执行的线程内存模型:每个方法被执行的时候,Java 虚拟机都会同步创建一个栈帧,用于存储局部变量表、操作数栈、动态连接、方法出口等信息。
方法从调用到结束就对应着一个栈帧从入栈到出栈的过程。在《Java 虚拟机规范》中,对该内存区域规定了两类异常:
- 如果线程请求的栈深度大于虚拟机所允许的栈深度,将抛出
StackOverflowError
异常; - 如果 Java 虚拟机栈的容量允许动态扩展,当栈扩展时如果无法申请到足够的内存会抛出
OutOfMemoryError
异常。
2.3 本地方法栈
本地方法栈(Native Method Stacks)与虚拟机栈类似,其区别在于:Java 虚拟机栈是为虚拟机执行 Java 方法(也就是字节码)服务的,而本地方法栈则是为 JVM 使用到的本地(Native)方法服务。
2.4 堆
堆(Java Heap)是虚拟机所管理的最大一块内存空间,它被所有线程所共享,用于存放对象实例。
Java 堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为是连续的。Java 堆可以被实现成固定大小的,也可以是可扩展的。
当前大多数主流的虚拟机都是按照可扩展来实现的,即可以通过最大值参数 -Xmx
和最小值参数 -Xms
回复