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. 保存临时值的位置不同
    (1)基于栈:将临时值保存在“求值栈”上
    (2)基于寄存器:将临时值保存在寄存器中
  2. 代码所占的体积不同
    (1)基于栈:代码紧凑,体积小,但所需代码条数多
    (2)基于寄存器:代码相对大些,但所需代码条数少
  3. “基于栈”中的“栈”指的是“求值栈”而不是“调用栈”
    (1)某些情况下两者是同一个栈
    (2)但在JVM中两者是不同的概念
    (3)JVM中“求值栈”被称为“操作数栈”( operand stack)
    (4)HotSpot把该栈称为“表达式栈”( expression stack)

JVM的方法调用栈

  1. 每个Java线程有一个Java方法调用栈,该栈不与其它线程共享
  2. 每个方法每次被调用时都会在方法调用栈上分配一个栈帧
    ◦ 作为该方法调用的“活动记彔”
    ◦ 存储局部数据(包括参数)、临时值、返回值等
    ◦ 也用于动态链接、分派异常等用途
    ◦ 栈帧大小在从Java源码编译为Class文件时已可以确定
    (1)记录在Class文件中每个方法的Code属性中
    (2)max_stack不max_locals
    (3)栈帧大小不需要在方法的执行当中变化
  3. 方法的一次调用结束时,对应的栈帧自动被撤销
    ◦ 无论是正常返回还是抛出异常

JVM的方法调用栈

  1. 每个Java栈帧包括:
    ◦ 局部变量区,保存参数与局部变量
    ◦ 操作数栈,保存表达式计算过程中的临时值
    ◦ 指向方法已解析的常量池的引用,用于动态链接、查找常量
    ◦ 其它一些VM内部实现需要的数据

在这里插入图片描述
如果一个方法的基本类型值传给另外一个方法,则前后两个栈帧可以共享一部分区域来传递参数。
在这里插入图片描述

栈帧中局部变量区的slot的复用

  1. 局部变量区在每个Java栈帧里都有一份
  2. 用于保存参数与局部变量
    ◦ 也可能用于临时保存返回值( finally)
    ◦ 也可能保持ret指令的返回地址
    ◦ 以slot为单位,每个slot至少32位宽
    ◦ double不long占两个slot,其它占一个
  3. 一个slot在一个方法中可以分配给多个变量使用
    ◦ 只要返些变量的作用域不重叠
    ◦ 变量类型是否相同没有关系
  4. 栈帧的第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的基本结构

主要包括一套运行时环境和两个编译器。

一套运行时环境

  1. 同一个解释器,高度优化的解释器,执行启动阶段代码及不常用代码;解释代码不编译后代码、本地代码共用同一个栈
  2. 同一组GC,有多种GC算法实现可供选择。
  3. 除编译器外,其它部分上同,不过client与server模式有不同的默认配置。

两个编译器

Client编译器( C1)

  1. 轻量,只做少量性能开销比高的优化,占用内存较少
  2. 适用于桌面交互式应用,如GUI应用
    Server编译器( C2,或称为Opto)
  3. 重量,大量应用传统编译优化技巧,占用内存相对多些
  4. 顶峰速度高
  5. 适用于服务器端应用。

启动程序

(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对象实例或数组实例

对象头

  1. markOop
    在这里插入图片描述
    markOop的内部结构。
    在这里插入图片描述
Compressed oop
  1. -XX:+UseCompressedOops,默认为false

  2. 在64位HotSpot中使用32位指针,3段式,根据-Xmx/-XX:MaxHeapSize、 -XX: HeapBaseMinAddress以及进程环境。
    3.

  3. 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虚拟机的主要内容,如果未能解决你的问题,请参考以下文章

java虚拟机和java内存区域概述

java虚拟机学习-触摸java常量池(13)

深入理解Java虚拟机:JVM高级特性与最佳实践的内容简介

android -------- java虚拟机和Dalvik虚拟机

Java虚拟机体系结构

JAVA虚拟机体系结构