Java虚拟机如何工作
Java虚拟机(或JVM)允许计算机解释或运行Java程序。它作为一个编译器,用于生成机器代码。所有Java程序都需要一个运行时环境。
如果你想让Java应用程序完全运行,你就需要一个JVM(Java虚拟机)。Java代码的主要方法是由JVM调用的,JVM是JRE(Java运行时环境)的一部分。
有一个Java应用程序的俚语叫做WORA(Write Once Run Anywhere)。因此,在一个系统上产生的Java代码可以在任何其他支持Java的系统上运行,而不需要任何改变。
简介
Java虚拟机(JVM)允许所有这些事情发生。具有相同名称的类文件由Java编译器生成,作为一个.java 文件的编译过程的一部分。
这个'.class'文件在执行时执行一连串的任务。下面的步骤描述了JVM的整体情况,我们将在本文中进一步讨论它们。
虚拟机的类型
- 基于系统的虚拟机(SVM)。作为物理计算机的替代品,SVM被开发出来。一台主机运行它们并使用它们的硬件资源。
- 基于应用的虚拟机(AVM)。主机允许单个进程作为一个应用程序执行,而不涉及任何硬件。基于进程的虚拟机是它们的另一个名字。JVM属于这组虚拟机,我们将在本文中详细讨论。
- 应用级虚拟机(AVM)。允许单个进程作为应用程序在主机上执行,没有任何硬件组件。因此,它们也被称为基于进程的虚拟机。
这个.class 文件将JVM分解成许多阶段,描述了它的工作原理。
- 类加载器
- JVM内存
- 执行引擎
- Java本地接口(JNI)
- 本地方法库 我们现在将从第一个阶段开始讨论下面的所有这些阶段。
类加载器子系统
类加载器有三个组成部分。
- 应用程序类加载器
- 扩展类加载器
- Bootstrap类加载器
作为JVM的一个阶段,类加载器主要由以下活动组成。
- 加载。ClassLoader将'.class'文件加载到方法区,并为类文件创建二进制数据。对于JVM来说,每个
.class文件的方法区域包含以下信息,这些信息至关重要。 - 类是以其超类或根类命名的。
.class文件可以被划分为类或接口。- 修改器、变量和方法上有很多细节。
对于每个加载的.class 文件,JVM会产生一个Class对象,在堆内存中代表它。人们应该注意到,生成的这个类对象属于Java.lang 包的。
如果程序员想知道一个类的信息,如它的名字、它的父级、或与之相关的任何方法/变量,他们可以使用这些Class对象。Object类的getClass()函数可以专门用来检索这些对象的引用。JVM构建的类对象在内存中表示.class 文件,在下面这个Java应用程序中演示。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Vehicle {
public static void main(String[] args)
{
car c1 = new car();
Class newcar1 = newcar1.getClass();
System.out.println(newcar1.getType());
Method m[] = newcar1.getDeclaredMethods();
for (Method method : m)
System.out.println(method.getType());
Field f[] = newcar1.getDeclaredFields();
for (Field field : f)
System.out.println(field.getType());
}
}
//We can get details about a particular class by using the Class object.
class car {
private String type;
private int id_No;
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public int getId_no() { return id_No; }
public void setId_no(int id_no)
{
this.id_No = id_no;
}
}
输出
car
getType
setType
getId_no
setId_no
type
id_No
请记住,加载一个'.class'文件只能创建一个类的实例。
- 链接。执行三个操作,包括。
- 准备:它分配内存并将其初始化为类变量的默认设置。
- 验证:只要文件的格式正确,并由一个有效的编译器创建,它就是正确的。当验证失败时,会抛出
java.lang运行时异常。在这种情况下,由ByteCodeVerifier组件负责。之后,该类文件就可以被编译了。 - 解决方法:对于符号引用的种类,有一个直接的替代方法,正如其名称所示。在方法区搜索被引用的实体就是这样完成的。
JVM使用Delegation-Hierarchy原则来加载类。加载请求被委托给扩展类加载器,而扩展类加载器又通过系统类加载器将请求委托给引导类加载器。任何其他没有通过扩展类加载器的请求都会通过系统类加载器(如果在引导路径中发现)。作为最后的手段,当系统类加载器不能加载所提供的类时,
java.lang运行时错误被抛出。
JVM内存
RAM也可以被称为Runtime Data Area (RDA)。根据JVM规范的规定,在程序执行过程中,有各种运行时数据区域必须存在。当JVM第一次启动时,会产生几个这样的对象。
可以构造和销毁线程特定对象。线程特定对象分别与一个线程一起生成和销毁。
它通常用于跟踪指令。
总的来说,JVM被分成五个子区域。
- 方法区:类的信息,如类名、父类名和方法都保存在方法区。
- 堆区:在堆区,所有对象的信息都被保存。每个Java虚拟机也有一个堆区,它也被认为是一种共享的资源。
- 栈区:这个堆栈的每一个块都被称为激活记录/堆栈框架,它将方法调用存储在其中的每一个块中。每个局部变量都有一个框架。JVM会在一个线程终止后销毁它的运行时堆栈,由于这个原因,它不是一个可供大众访问的资源。
- PC寄存器:存储线程当前指令的地址。每个线程都有其PC寄存器,正如你所期望的那样。
- 本机方法区:每个线程都有它的本地堆栈,存储关于本地方法参数的信息。
执行引擎
为了运行一个.class 文件,你需要一个执行引擎。例如,从文件中读取字节码,使用各种内存区域的数据,然后执行指令。
它由下面命名的三个组件组成。
- 解释器:本质上,解释器采取字节码并将其翻译成机器代码。解释器在运行一行字节码时可能比执行整个代码时更快。而且,每次调用同一方法时,都必须提供一个新的解释。
- JIT编译器(Just In Time compiler):执行引擎使用解释器来执行字节码。JIT编译器将代替执行引擎来检测一个方法是否重复。
JIT编译器由以下部分组成。
- 中间代码生成器。
- 代码优化器。
- 目标代码生成器。
- 分析器。
- 垃圾收集器(GC)。没有被引用的对象可以被垃圾收集器作为后台进程删除,释放出堆上的空间。
Java本地接口(JNI)
与本地方法库交互,提供本地库(C、C++)的执行,特定硬件的C/C++库可以因此而调用和被JVM调用。
本地方法库是一组执行引擎所需的本地库(C、C++)。
结论
虚拟机并不是基于现实的,但它们可以让你觉得它们是基于现实的。当需要编译Java代码时,机器会使用Java虚拟机进行编译,并允许Java应用程序运行。