JVM-Java虚拟机

一、JVM简介

1.1 什么是JVM

  • JVM是一个虚构出来的,在Java编译器和OS平台之间的虚拟处理器,是通过在实际的计算机上仿真模拟各种功能实现的,可在上面执行字节码程序
  • Java编译器面向JVM,生成JVM能理解的字节码文件。Java源文件经编译成字节码程序,通过JVM将每条指令翻译成不同的机器码,通过指定平台进行
  • JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。(JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行)。

在这里插入图片描述

1.2 JVM结构

Java虚拟机由三个子系统构成,分别是类加载子系统、JVM运行时数据区和执行引擎。
如下图所示:
在这里插入图片描述
以下分部分展示各个部分的作用:
在这里插入图片描述

  1. 类加载子系统负责从文件系统或者网络中加载类信息,加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)。
  2. 垃圾回收系统是Java虚拟机的重要组成部分,垃圾回收器可以对方法区、Java堆和直接内存进行回收。其中Java堆是垃圾收集器的工作重点。和C/C++不同,Java中所有的对象空间释放都是隐式的,也就是说,Java中没有类似free或者delete这样的函数释放指定的内存区域。对于不再使用的垃圾对象,垃圾回收系统会在后台默默工作,默默查找、标识并释放垃圾对象,完成包括Java堆、方法区和直接内存中的全自动化管理。
  3. 执行引擎是Java虚拟机的最核心组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成字节码后再执行。

关于运行时数据区中各部分的介绍,见:
Java内存介绍-运行时数据区

1.3 JVM执行程序的过程

  1. 加载.class文件
  2. 管理并分配内存
  3. 执行垃圾收集

JRE(Java运行时环境)是由JVM构造的Java程序的运行环境。JRE同时也是操作系统的一个应用程序、一个进程。因此JRE有它自己的生命周期、代码和数据空间。

JVM在整个jdk中处于最底层,负责与操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也叫虚拟机。

操作系统装入JVM是通过jdk中的Java.exe来完成,通过以下四步来创建JVM环境:

  1. 创建JVM装载环境和配置
  2. 装载JVM.dll
  3. 初始化JVM.dll并挂载到JNIENV(JNI调用接口)实例
  4. 调用JNIENV实例装载并处理class类

1.4 JVM的生命周期

JVM实例对应了一个独立运行的Java程序,因此它是进程级别

  • 启动:启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点
  • 运行:main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,Java程序也可以表明自己创建的线程是守护线程
  • 消亡:当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出

JVM执行引擎实例则对应了属于用户运行程序的线程,它是线程级别的

Java代码具体执行过程如下所示:
Java代码具体执行过程如下图:

二、JVM具体结构

2.2 Java栈

2.2.1 局部变量表

局部变量表是栈帧的重要组成部分之一。它用于保存函数的参数以及局部变量,局部变量表中的变量只在当前函数调用中有效,当函数调用结束,随着函数栈帧的弹出销毁,局部变量表也随之销毁。

由于局部变量表在栈帧中,因此,如果函数的参数和局部变量很多,会使得局部变量表膨胀,从而每一次函数调用就会占用更多的栈空间,最终导致函数的嵌套调用次数减少,每个方法所需要分配的局部变量表的最大容量在将Java编译为class文件时已经确定,在运行期间不会发生改变

局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象的引用(reference类型,不等同于对象本身,根据不同的虚拟机实现,可能是一个指向对象起始地址的引用指针,也可能是一个代表对象的句柄或者其他与对象相关的位置)和 returnAdress类型(指向下一条字节码指令的地址)。局部变量表所需的内存空间在编译期间完成分配,在方法在运行之前,该局部变量表所需要的内存空间是固定的,运行期间也不会改变。

局部变量表的容量以变量槽为最小单位,每个变量槽可以存储32位长度的内存空间。对于64位长度的数据类型(long,double),虚拟机会以高位对齐的方式为其分配两个连续的变量槽空间。

虚拟机通过索引定位的方法查找相应的局部变量。

2.2.2 操作数栈

操作数栈是虚拟机栈中的一个用于计算的临时数据存储区,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,当一个方法刚开始执行的时候,操作数栈中是空的,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。

2.2.3 动态链接

在一个class文件中,一个方法要调用其他方法,需要将这些方法的符号引用转化为其在内存地址中的直接引用,而符号引用存在于运行时常量池。

在每个栈帧中都包含一个指向运行时常量池中该栈所属方法的符号引用。

这些符号引用一部分会在类加载阶段或者第一次使用时就直接转化为直接引用,这类转化称为静态解析。另一部分将在每次运行期间转化为直接引用,这类转化称为动态链接。

2.2.4 方法返回

一个方法开始执行后,只有两种退出方式:正常完成出口和异常完成出口。正常完成出口指方法正常完成并退出,根据当前方法返回的字节码指令,这时有可能会有返回值传递给方法调用者调用它的方法),或者无返回值。异常完成出口指方法执行过程中遇到异常,并且这个异常方法在方法体内部没有得到处理,导致方法退出。

无论采用何种退出方式,在方法退出后,都需要返回到方法被调用的位置,方法返回时可能需要在栈帧中保存一些信息。

一般来说,方法正常退出时,调用者的程序计数器的值可以作为返回地址,栈帧中会保存这个计数器值。而方法异常退出时,返回地址要通过异常处理器表来确定,栈帧中一般不保存这部分信息。

2.2.5 附加信息

虚拟机规范允许具体的虚拟机实现增加一些规范中没有描述的信息到栈帧之中,例如和调试相关的信息,这部分信息完全取决于不同的虚拟机实现。

在实际开发中,一般会把动态链接,方法返回地址与其他附加信息一起归为一类,称为栈帧信息。

2.5 方法区

方法区和堆一样所有线程共享,主要用于存储已被jvm加载的类信息、常量(final关键字,值一旦被确定就无法改变)、静态变量、即时编译器编译后的代码等数据(在JDK1.7发布的HotSpot中,已经把字符串常量移除出方法区了)。

方法区存放着class文件的信息,还包括用来存储class常量的常量池(存储编译期间生成的字面量和符号引用),同时方法区还存在着运行时常量池(每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。并非class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法):
在这里插入图片描述

2.5.1 class文件中的常量池

class文件常量池用来存放两大类常量:字面量和符号引用量,字面量相当于Java语言的常量,如声明为final的常量等,符号引用包括以下三种:
类和接口的全限定名
字段名称和描述符
方法名称和描述符

2.5.2 方法区中的运行常量池

class文件中的常量池中的内容会在类加载后进入方法区的运行时常量池。相对于class文件中的常量池,运行时常量池的重要特征是具有动态性,Java并不要求常量只有在编译器才会产生,运行期间也可以将新的常量放入池中,这种特性用的最多的是String类中的intern()方法。

2.5.3 常量池的作用

常量池是为了避免频繁的创建和销毁对象造成系统性能的浪费,实现了对象的共享。

2.5.4 常量池的应用

对于byte、short、long、char、boolean对应的包装器类型都具有对应的常量池,这五种包装器类默认创建在-128到127的对象会放在缓存中,对于两种浮点数没有实现常量池技术。

参考:
https://www.cnblogs.com/zwbg/p/6194470.html
https://www.cnblogs.com/chenpt/p/8953435.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值