黑马程序员技术交流社区
标题:
【记上海校区编码的日子】Java JVM概述
[打印本页]
作者:
fiypig688
时间:
2018-10-22 15:22
标题:
【记上海校区编码的日子】Java JVM概述
Java JVM概述
一、Java 虚拟机概述
1、什么是虚拟机和 Java 虚拟机
虚拟机
• 定义:模拟某种计算机体系结构,执行特定指令集的软件
• 系统虚拟机( Virtual Box、VMware),进程虚拟机
进程虚拟机
• JVM、Adobe Flash Player、FC模拟器
高级语言虚拟机
• JVM、.NET CLR、P-Code(由加州大学圣地亚哥分校(University of California, San Diego,UCSD)于1978年发布的高度可移植、机器无关的、运行Pascal语言的虚拟机)
Java 语言虚拟机
• 可以执行 Java 语言的高级语言虚拟机。 Java 语言虚拟机并不一定就可以称为 JVM,譬如:Apache Harmony
Java™ 虚拟机
• 必须通过 Java TCK(Technology Compatibility Kit)的兼容性测试的Java语言虚拟机才能称为“Java™ 虚拟机”
• Java™ 虚拟机并非一定要执行“Java”程序
目前业界三大商用 JVM:Oracle HotSpot 、 Oracle JRockit VM、IBM J9 VM
Java虚拟机
Java虚拟机是整个Java平台的基石,是Java技术用以实现硬件无关与操作系统无关的关键部分,是Java语言生成出极小体积的编译代码的运行平台,是保障用户机器免于恶意代码损害的保护屏障。
Java虚拟机可以看作是一台抽象的计算机。如同真实的计算机那样,它有自己的指令集以及各种运行时内存区域。
使用虚拟机来实现一门程序设计语言有许多合理的理由,业界中流传最为久远的虚拟机可能是UCSD Pascal的P-Code虚拟机。
第一个Java虚拟机的原型机是由Sun Microsystems公司实现的,它被用在一种类似PDA(Personal Digital Assistant,俗称掌上电脑)的手持设备上仿真实现Java虚拟机指令集。时至今日,Oracle已有许多Java虚拟机实现应用于移动设备、桌面电脑、服务器等领域。
Java虚拟机并不局限于特定的实现技术、主机硬件和操作系统,Java虚拟机也不局限于特定的代码执行方式,它不强求使用解释器来执行程序,也可以通过把自己的指令集编译为实际CPU的指令来实现,它可以通过微代码(Microcode)来实现,或者甚至直接实现在CPU中。
Java虚拟机与Java语言并没有必然的联系,它只与特定的二进制文件格式——Class文件格式所关联,Class文件中包含了Java虚拟机指令集(或者称为字节码、Bytecodes)和符号表,还有一些其他辅助信息。
基于安全方面的考虑,Java虚拟机要求在Class文件中使用了许多强制性的语法和结构化约束,但任一门功能性语言都可以表示为一个能被Java虚拟机接收的有效的Class文件。作为一个通用的、机器无关的执行平台,任何其他语言的实现者都可以将Java虚拟机作为他们语言的产品交付媒介。
Oracle HotSpot 虚拟机
1999年4月27日,HotSpot虚拟机发布,HotSpot最初由一家名为“Longview Technologies”的小公司开发,因为HotSpot的优异表现,这间公司在1997年被Sun公司收购了。HotSpot虚拟机发布时是作为JDK 1.2的附加程序提供的,后来它成为了JDK 1.3及之后所有版本的Sun JDK的默认虚拟机。
HotSpot VM相信所有Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。但不一定所有人都知道的是,这个目前看起来“血统纯正”的虚拟机在最初并非由Sun公司开发,而是由一家名为“Longview Technologies”的小公司设计的;甚至这个虚拟机最初并非是为Java语言而开发的,它来源于Strongtalk VM,而这款虚拟机中相当多的技术又是来源于一款支持Self语言实现“达到C语言50%以上的执行效率”的目标而设计的虚拟机,Sun公司注意到了这款虚拟机在JIT编译上有许多优秀的理念和实际效果,在1997年收购了Longview Technologies公司,从而获得了HotSpot VM。
HotSpot VM既继承了Sun之前两款商用虚拟机的优点(如准确式内存管理),也有许多自己新的技术优势,如它名称中的HotSpot指的就是它的热点代码探测技术(这里的描写带有“历史由胜利者书写”的味道,其实两个VM基本上是同时期的独立产品,HotSpot还稍早一些,HotSpot一开始就是准确式GC,而Exact VM之中也有与HotSpot几乎一样的热点探测,为了Exact VM和HotSpot VM哪个成为Sun主要支持的产品VM,在Sun公司内部还大吵过一场,HotSpot打败Exact并不能算技术上的胜利),HotSpot VM的热点代码探测能力可以通过执行计数器找出最具优编译价值的代码,然后通知JIT编译器以方法为单位进行编译。
如果一个方法被频繁调用,或方法中有效循环次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。
通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无需等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。
2006年的JavaOne大会上,Sun宣布最终会把Java开源,并在随后的一年,陆续地将JDK的各个部分(其中当然也包括了HotSpot VM)在GPL协议下公开了源码,并在此基础上建立了OpenJDK。这样,HotSpot VM便成为了Sun JDK和OpenJDK两个实现极度接近的JDK项目的共同虚拟机。
在2008年和2010年,Oracle分别收购了BEA和Sun公司,这样Oracle就同时拥有了这个星球上最优秀的两款Java虚拟机:JRockit VM和HotSpot VM。
Oracle宣布在不久的将来(大约应在JDK 8的时候)会完成这两款虚拟机的整合工作,使之优势互补。整合的方式大致上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,使用HotSpot的JIT编译器与混合的运行时系统。当HotSpot吸收了JRockit的全部功力之后,能否一统虚拟机的江湖,成为真正的武林盟主,我们拭目以待。
2、JVM 虚拟机基础架构
该图参考了网上广为流传的JVM构成图,整个JVM分为四部分:
Class Loader 类加载器
Execution Engine 执行引擎
Native Interface本地接口
Runtime data area运行数据区
3、JVM 虚拟机运行时数据区
JVM 虚拟机运行时数据区
• 在《Java 虚拟机规范》中定义了若干种程序运行期间会使用到的存储不同类型数据的区域。
• 有一些区域是全局共享的,随着虚拟机启动而创建,随着虚拟机退出而销毁。有一些区域是线程私有的,随着线程开始和结束而创建和销毁。
• 是所有 JVM 虚拟机共同的内存区域概念模型
运行时数据区的划分,如下图:
• 程序计数器
• 堆
• JVM虚拟机栈
• 本地方法栈
• 方法区
4、程序计数器区域
程序计数器(Program Counter Register)
• 一块较小的的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。
• 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器值则为空。
• 此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError情况的区域。
在虚拟机的概念模型里,字节码解释器工作时就是通过在改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
由于Java虚拟机的多线程是通过线程轮流切换,分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。
因此为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
二、JVM 虚拟机栈和本地方法栈
1、JVM 虚拟机栈的概念和特征
JVM 虚拟机栈的特征
• 线程私有
• 后进先出(LIFO)栈
• 存储栈帧,支撑 Java 方法的调用、执行和退出
• 可能出现 OutOfMemoryError 异常和 StackOverflowError 异常
2、本地方法栈的概念和特征
JVM 本地方法栈的特征
• 线程私有
• 后进先出(LIFO)栈
• 作用是支撑 Native 方法的调用、执行和退出
• 可能出现 OutOfMemoryError 异常和 StackOverflowError 异常
• 有一些虚拟机(如 HotSpot)将 Java 虚拟机栈和本地方法栈合并实现
3、栈帧概念和特征
栈帧的概念和特征
• JVM 虚拟机栈中存储的内容,它被用于存储数据和部分过程结果的数据结构,同时也被用来处理动态链接、方法返回值和异常分派
• 一个完整的栈帧包含:局部变量表、操作数栈、动态连接信息、方法正常完成和异常完成信息
局部变量表概念和特征
• 由若干个 Slot 组成,长度由编译期决定
• 单个Slot可以存储一个类型为 boolean、byte、char、short、float、reference 和 return Address 的数据,两个Slot可以存储一个类型为long或double的数据。
• 局部变量表用于方法间参数传递,以及方法执行过程中存储基础数据类型的值和对象的引用
操作数栈的概念和特征
• 是一个后进先出栈,由若干个 Entry 组成,长度由编译期决定
• 单个 Entry 即可以存储一个 Java 虚拟机中定义的任意数据类型的值,包括 long和 double 类型,但是存储 long 和 double 类型的 Entry 深度为2,其他类型的深度为1
• 在方法执行过程中,栈帧用于存储计算参数和计算结果;在方法调用时,操作数栈也用来准备调用方法的参数以及接收方法返回结果
5、内存异常
JVM 虚拟机栈和本地方法栈可能发生如下异常情况:
• 如果线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量时,JVM 虚拟机将会抛出一个 StackOverflowError 异常。
• 如果 JVM 虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈,那 JVM 虚拟机将会抛出一个 OutOfMemoryError 异常。
三、JVM 堆
1、JVM 堆的概念
JVM 堆的特征
• 全局共享
• 通常是 JVM 虚拟机中最大的一块内存区域
• 作用是做为 Java 对象的主要存储区域
• JVM 明确要求该区域需要实现自动内存管理,即常说的 GC,但并不限制采用哪种算法和技术去实现
• 可能出现 OutOfMemoryError 异常
3、JVM 堆内存异常
JVM 堆可能发生如下异常情况:
• 如果实际所需的堆超过了自动内存管理系统能提供的最大容量,那 JVM 虚拟机将会抛出一个 OutOfMemoryError 异常。
四、方法区和运行时常量池
1、方法区的概念
方法区的特征
• 全局共享
• 作用是存储 Java 类的结构信息
• JVM 不要求该区域实现自动内存管理,但是商用 Java 虚拟机都能够自动管理该区域的内存
• 可能出现 OutOfMemoryError 异常
2、运行时常量池的概念
运行时常量池的特征
• 全局共享
• 是方法区的一部分
• 作用是存储 Java 类文件常量池中的符号信息
• 可能出现 OutOfMemoryError 异常
3、HotSpot 方法区实现的变迁
永久代与方法区
• 在 JDK 1.2 ~ JDK 6,HotSpot 使用永久代实现方法区
• 在 JDK 7 开始,HotSpot 开始了移除永久代的计划
- 符号表被移到 Native Heap 中
- 字符串常量和类的静态引用被移到 Java Heap 中
• 从 JDK 8 开始,永久代已被元空间(Metaspace)所代替
元空间与永久代的区别:
元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:
-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集 。
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集。
作者:
fiypig688
时间:
2018-10-22 15:29
欢迎交流和学习
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2