JVM知识(上)

java虚拟机被称为“虚拟”,因为它是一个抽象的计算机定义的规范。要运行一个Java程序,需要一个抽象的规范的具体实现。以下内容主要还是参考《Inside JVM》

什么是JVM?

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM三种不一样的地方:抽象的规范,一个具体的实现,运行时的实例。

JVM的生命周期

java虚拟机种运行的一个实例有着明确的“使命”:运行一个java程序,当程序启动时,产生一个运行实例,当程序运行完成时,实例就没了。如果同时启动三个java程序,在同一台电脑上,使用相同的实现方法,你就会得到三个java虚拟机的实例,每个java程序运行在自己的虚拟机实例上面。

Java虚拟机实例通过调用一些初始类的main()方法来开始运行其单独应用程序,该main()方法必须时公共(public),静态(static),无返回值的(void),并且接受一个字符串数组的参数(String[] args),按照上面定义的main()方法,任何一个类的main方法都可以作为程序启动的起点。


public class Application {
      public static void main(String[] args) {
         SpringApplication.run(Application.class, args);
      }
}

在java虚拟机中,线程分两种:守护线程(daemon,也可以成为后台线程)和 非守护线程(non-daemon,前台线程)。


daemon守护线程是JVM自己用的,就比如我们常说的垃圾回收。non-daemon非守护线程,应用程序启动了main(),然后再调用我们自己写的方法。

一个java程序在运行时,只要非守护线程一直运行,那么java虚拟机实例就一直存在,当所有的java非守护线程中断时,java虚拟机实例也就消失了。当然我们也可以直接通过类Runtime或者类System调用exit()方法来使程序中断。

JVM的体系结构

在java虚拟机规范中,java虚拟机的行为是由子系统,内存区域,数据类型和指令来描述的。这些组件的目的与其说是决定内部架构的实现,更提供了一种严格定义的外部行为的实现。规范定义了所需的任何Java虚拟机的行为来实现这些抽象组件及其之间的交互。

一个Java虚拟机,包括主要的子系统和内存区域中描述的规范如前一章中提到,每个Java虚拟机有一个类装入器子系统:加载机制类型(类和接口)指定完全限定的名称。每个Java虚拟机还提供一个执行引擎:一种机制负责执行的指令包含在加载的类的方法。

当一个Java虚拟机运行一个程序的时候,他需要内存存储更多的东西,包括直接码和其它信息摘录加载类文件,程序实例化对象,参数方法,返回值,局部变量,计算的中间结果。虽然相同的数据区域运行在每一个java虚拟机的实现上,规范是抽象的,但具体运行这些数据区域的细节的时候还是需要(设计者)实现者来具体实现。
不同的java虚拟机的实现有很多不同的内存限制,有些实现需要很多的内存为其工作,而有的实现却需要的很少;有的实现可以利用java虚拟内存,有的却不可以;运行时数据区域的抽象性质规范更容易在各种各样的电脑和设备实现Java虚拟机。
一些运行时的数据区被一个程序线程或者其它独一无二的线程所共享,每一个java虚拟机实例都有一个方法区(method area)和堆(heap)。这些区域内运行的所有线程共享虚拟机。当JVM加载一个类文件(class文件)时,JVM会从二进制数据中解析出包含信息类型的类文件。它会把这些类的文件送到方法区里面去。当程序运行时,虚拟机将所有对象实例化到堆(heap)。

因为每个新线程启动,它有自己的电脑注册(程序计数器)和Java堆栈。如果线程正在执行Java方法(不是一个本地方法),pc寄存器的值显示为要执行下一个指令。Java堆中存储着Java线程(非原生)方法调用的状态。Java方法调用的状态包括局部变量、被调用的参数,它的返回值(如果有的话),中间的计算。本地方法调用的状态以具体实现相关的方式在本地方法栈存储着,以及可能在寄存器或其他具体实现相关的内存区域。Java堆栈由堆栈帧(帧)组成。一个堆栈帧包含一个Java方法调用的状态,说白了就是每个栈就是一个每个调用的方法。当一个线程调用一个方法时,Java虚拟机会分配一个新的栈给那个线程的方法。当方法完成时,虚拟机就会丢弃此方法的栈。Java虚拟机没有寄存器来保存中间数据值。指令集被使用在Java堆栈存储这些中间数据值。

上图中,线程1和2是执行java方法,线程3 执行本地的方法。

JVM的数据类型

Java虚拟机通过操作某些类型的数据来进行计算。这些数据类型和操作都严格定义的Java虚拟机规范。可以分为一组基本类型和引用类型。变量的原始类型保存原始值,变量的引用类型值的引用。引用值引用对象,但不是对象本身。原始值,相比之下,不参考任何东西。他们是实际数据本身。

所有原始类型的Java编程语言,除了布尔类型,其它都是是Java虚拟机的基本类型。编译器将Java源代码转换为字节码时,它使用int或字节来表示布尔值。在Java虚拟机中,错误的是由整数0和真正的任何非零的整数,业务涉及到布尔值使用int。布尔访问数组作为字节数组,尽管它们可能在堆上表示为字节数组或字段。原始类型的Java编程语言以外的布尔形成了数字类型的Java虚拟机。之间的数值类型为: byte, short, int, long, , char。与Java编程语言一样,Java虚拟机的基本类型有相同的范围。长在Java虚拟机总是像一个64位表示整数,独立于底层主机平台。Java程序员可以使用适用于Java虚拟机而不在原始类型中的returnValue类型。这种原始的类型在Java程序被使用。引用类型分为三种:类类型,接口类型和数组类型。所有三种类型值对动态创建对象的引用。class type值对类实例的引用。array type值是数组的引用,这是成熟的对象在Java虚拟机。interface type值是实现一个接口的类实例的引用。另一个值是null值的引用,这表明没有引用任何对象的引用变量。Java虚拟机规范定义了每个数据类型的值的范围,但没有定义他们的大小。bits比特数用来存储每个数据类型。

下篇将详细介绍JVM中heap,stack,method area如何工作的

posted @ 2018-08-19 18:02  Levcon  阅读(170)  评论(0编辑  收藏  举报