Java虚拟机
Posted gonghaiyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java虚拟机相关的知识,希望对你有一定的参考价值。
本节内容只包括概念中的虚拟机,不包括具体实现。
什么是虚拟机
虚拟机是模拟执行某种指令集体系结构的软件。可分为三类。(1)进程虚拟机,如java虚拟机。(2)系统虚拟机,如visualbox,vm。(3)协设计虚拟机,如FPGA有人模拟了虚拟机协处理器(包括二进制翻译器以及TCache等部件单元)。
什么是java虚拟机
java虚拟机有多层含义。包括:
(1)一套规范: Java虚拟机规范用于定义概念上Java虚拟机的行为表现。
(2)一种实现:例如HotSpot, J9, JRockit。(a)需要实现JVM规范。(b)但具体实现方式不需要与“概念中”的JVM一样。注意:只有通过JCK测试的才可以合法的称为Java™ VM。
(3)一个运行中的实例,某个JVM实现的某次运行的实例。
只要输入为符合规范的Class文件即可执行。不一定用java语言编写,目前java虚拟机能运行的语言有:Scala、 Clojure、 Groovy、 Fantom、 Fortress、 Nice、 Jython、 JRuby、 Rhino、Ioke、 Jaskell、( C、 Fortran …)等。
概念中Java虚拟机的基本结构
下面重点关注执行引擎。
Java虚拟机的基本特征
(1)基于栈的体系结构
(2)动态加载程序,运行时根据需要加载class文件。
(3)安全性
(4)自动内存管理
(5)多线程支持
(6)与本地库的交互
Java虚拟机字节码
(1)相当于传统编译器中的中间代码。
(2)基于栈的指令集体系结构。使代码变得紧凑,方便实现高可移植的解释器。
(3)字节码对应Java源代码中的语句与表达式的后缀记法(逆波兰记法)。
(4)指令不定长,在1-4字节间变动。
Java虚拟机字节码设计目标
(1)易于校验(安全性)
(2)易于编译(高性能)
(3)易于解释执行(实现门槛低)
(4)易于移植
(5)包含大量类型信息
Java虚拟机字节码指令类别
(1)局部变量读/写
(2)算术与类型转换
(3)条件/无条件跳转
(4)对象创建和操作
(5)数组创建和操作
(6)方法调用
(7)栈操作(操作数栈)
基于栈不基于寄存器的体系结构的区别
- 保存临时值的位置不同
(1)基于栈:将临时值保存在“求值栈”上
(2)基于寄存器:将临时值保存在寄存器中 - 代码所占的体积不同
(1)基于栈:代码紧凑,体积小,但所需代码条数多
(2)基于寄存器:代码相对大些,但所需代码条数少 - “基于栈”中的“栈”指的是“求值栈”而不是“调用栈”
(1)某些情况下两者是同一个栈
(2)但在JVM中两者是不同的概念
(3)JVM中“求值栈”被称为“操作数栈”( operand stack)
(4)HotSpot把该栈称为“表达式栈”( expression stack)
JVM的方法调用栈
- 每个Java线程有一个Java方法调用栈,该栈不与其它线程共享
- 每个方法每次被调用时都会在方法调用栈上分配一个栈帧
◦ 作为该方法调用的“活动记彔”
◦ 存储局部数据(包括参数)、临时值、返回值等
◦ 也用于动态链接、分派异常等用途
◦ 栈帧大小在从Java源码编译为Class文件时已可以确定
(1)记录在Class文件中每个方法的Code属性中
(2)max_stack不max_locals
(3)栈帧大小不需要在方法的执行当中变化 - 方法的一次调用结束时,对应的栈帧自动被撤销
◦ 无论是正常返回还是抛出异常
JVM的方法调用栈
- 每个Java栈帧包括:
◦ 局部变量区,保存参数与局部变量
◦ 操作数栈,保存表达式计算过程中的临时值
◦ 指向方法已解析的常量池的引用,用于动态链接、查找常量
◦ 其它一些VM内部实现需要的数据
如果一个方法的基本类型值传给另外一个方法,则前后两个栈帧可以共享一部分区域来传递参数。
栈帧中局部变量区的slot的复用
- 局部变量区在每个Java栈帧里都有一份
- 用于保存参数与局部变量
◦ 也可能用于临时保存返回值( finally)
◦ 也可能保持ret指令的返回地址
◦ 以slot为单位,每个slot至少32位宽
◦ double不long占两个slot,其它占一个 - 一个slot在一个方法中可以分配给多个变量使用
◦ 只要返些变量的作用域不重叠
◦ 变量类型是否相同没有关系 - 栈帧的第0个位置是this指针,用于指向该方法所在类的实例。
示例:
因为l后面没有用到,当执行出了l所在的大括号,在执行while时,slot4、slot5为空。
Sun HotSpot虚拟机
Sun实现的一种桌面版JVM,从JDK1.3开始成为Sun JDK的默认VM。主要使用C++实现,JNI接口部分用C实现。拥有先进的解释器、动态编译器与GC(GC在不断的迭代更新中)。解释器与编译器结合的混合执行模型,默认启动时解释执行,对热点代码进行编译执行,故名“HotSpot VM"。从2006年底开源,并包含在OpenJDK中。
JVM在哪里?
java.exe是java的启动程序,通过启动程序加载jvm.dll。并调用jvm.dll进行class文件执行处理。
HotSpot VM的基本结构
主要包括一套运行时环境和两个编译器。
一套运行时环境
- 同一个解释器,高度优化的解释器,执行启动阶段代码及不常用代码;解释代码不编译后代码、本地代码共用同一个栈
- 同一组GC,有多种GC算法实现可供选择。
- 除编译器外,其它部分上同,不过client与server模式有不同的默认配置。
两个编译器
Client编译器( C1)
- 轻量,只做少量性能开销比高的优化,占用内存较少
- 适用于桌面交互式应用,如GUI应用
Server编译器( C2,或称为Opto) - 重量,大量应用传统编译优化技巧,占用内存相对多些
- 顶峰速度高
- 适用于服务器端应用。
启动程序
(1)Windows: java.exe / POSIX: java。
(2)载入JVM( jvm.dll / libjvm.so)
(3)设置启劢参数
(4)初始化JVM
(5)找到主类, main方法,检查signature。
(6)通过JNI调用main方法。
(7)设置类路径。-Djava.class.path,Windows上设置的类路径顺序与字符串顺序相同, Linux上则相反(实现细节)
HotSpot中的Java对象布局
由两个参数控制。
Java对象实例或数组实例
对象头
- markOop
markOop的内部结构。
Compressed oop
-
-XX:+UseCompressedOops,默认为false
-
在64位HotSpot中使用32位指针,3段式,根据-Xmx/-XX:MaxHeapSize、 -XX: HeapBaseMinAddress以及进程环境。
-
klassOop
如果是数组,Java数组类型不包含数组长度信息,因而只看数组类型无法确定数组实例的大小,必须在数组实例内嵌入_length字段来记录数组长度。
对象实际数据
填充方式
实例
如下两个Integer类型,同时指向方法区的klassOopDesc对象。
在内存中的结构如下,示意图。
HotSpot中的Java方法相关对象
HotSpot里的线程
在以下的线程中,有Finalizer和ReferenceHandler线程是通过java代码实现的。
HotSpot线程交互实验
待完成。。。
参考
jvm规范:https://docs.oracle.com/javase/specs/
jvm中的动态类加载论文:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.18.762
jvm白皮书:https://www.oracle.com/java/technologies/javase/javase-core-technologies-apis.html
java对象布局:https://www.oracle.com/java/technologies/whitepaper.html
jvm中的oops:http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html
jvm中oop与klass:http://openjdk.java.net/groups/hotspot/docs/FOSDEM-2007-HotSpot.pdf
jvm中压缩对象指针:http://wikis.sun.com/display/HotSpotInternals/CompressedOops
jvm中Finalizer线程:http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/tip/src/share/classes/java/lang/ref/Finalizer.java
jvm中Reference线程:http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/tip/src/share/classes/java/lang/ref/Reference.java
jvm中的线程交互:http://download.oracle.com/javase/6/docs/technotes/tools/share/jstack.html
jvm线程调用栈:http://www.atmarkit.co.jp/fjava/rensai3/javavm01/javavm01_1.html
c2编译器:http://ssw.jku.at/General/Staff/TW/igv.html
以上是关于Java虚拟机的主要内容,如果未能解决你的问题,请参考以下文章