JVM如何工作

JVM(Java虚拟机)充当运行Java应用程序的运行时引擎。JVM实际上调用主要的方法存在于java代码中。JVM是JRE(Java运行时环境)的一部分。

Java应用程序被称为WORA(Write-Once-Run-Anywhere)。这意味着程序员可以在一个系统上开发Java代码,并且可以期望它在任何其他支持Java的系统上运行,而不需要任何调整。这一切都有可能是因为JVM。

当我们编译一个.java语言文件,.class文件存在具有相同类名的文件(包含字节码).java语言文件由Java编译器生成。这个.class当我们运行这个文件时,它会进入不同的步骤。这些步骤共同描述了整个JVM。

 虚拟机

1、类加载器子系统

它主要负责三项活动。

  • 加载
  • 连接
  • 初始化

加载:类加载器读取.class文件,生成相应的二进制数据并保存在方法区。在每一个.class文件中,JVM将以下信息存储在Method Area(方法区)中。

  • 加载的类及其直接父类的完全限定名。
  • .class文件是否与Class或Interface或Enum相关
  • 修饰符、变量和方法信息等。

装载.class文件后,JVM会创建一个Class类型的对象来在Heap(堆内存)中表示该文件。请注意,该对象的类型为java.lang包中预定义的Class。这个类对象可以被程序员用来获取类级别的信息,如类名、父类名称、方法和变量信息等。

// A Java program to demonstrate working of a Class type 
// object created by JVM to represent .class file in 
// memory. 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 

// Java code to demonstrate use of Class object 
// created by JVM 
public class Test 
{ 
    public static void main(String[] args) 
    { 
        Student s1 = new Student(); 

        // Getting hold of Class object created 
        // by JVM. 
        Class c1 = s1.getClass(); 

        // Printing type of object using c1. 
        System.out.println(c1.getName()); 

        // getting all methods in an array 
        Method m[] = c1.getDeclaredMethods(); 
        for (Method method : m) 
            System.out.println(method.getName()); 

        // getting all fields in an array 
        Field f[] = c1.getDeclaredFields(); 
        for (Field field : f) 
            System.out.println(field.getName()); 
    } 
} 

// A sample class whose information is fetched above using 
// its Class object. 
class Student 
{ 
    private String name; 
    private int roll_No; 

    public String getName() { return name; } 
    public void setName(String name) { this.name = name; } 
    public int getRoll_no() { return roll_No; } 
    public void setRoll_no(int roll_no) { 
        this.roll_No = roll_no; 
    } 
} 

输出:

Student
getName
setName
getRoll_no
setRoll_no
name
roll_No

注意:对于每个加载的.class文件,仅创建一个Class对象。

Student s2 = new Student();
// c2 will point to same object where 
// c1 is pointing
Class c2 = s2.getClass();
System.out.println(c1==c2); // true

链接:执行验证、准备和(可选)解析。

  • 验证:它确保.class文件,即检查该文件是否由有效的编译器正确格式化和生成。如果验证失败,我们将得到运行时异常java.lang.verify错误.
  • 准备:JVM为类变量分配内存,并将内存初始化为默认值。
  • 解析:这是将类型中的符号引用替换为直接引用的过程。它是通过搜索方法区域来定位被引用实体来完成的。

初始化:在这个阶段,所有的静态变量都被分配给代码和静态块(如果有的话)中定义的值。它在类中从上到下执行,在类层次结构中从父到子执行。
一般来说,有三类装载机:

  • 引导类加载器(Bootstrap class loader):每个类都必须有一个可信任的引导装入器实现。它加载的核心java API位于JAVA_HOME/jre/lib目录下。此路径通常称为引导路径。它是用C、C++等本机语言实现的。
  • 扩展类加载器(Extension class loader):它是引导类加载器的子级。它加载扩展目录中的类JAVA_HOME/jre/lib/ext(扩展路径)或java.ext.dirs系统属性指定的任何其他目录。它由$sun.misc.Launcher$ExtClassLoader class实现
  • 系统/应用程序类加载器(System/Application class loader):它是扩展类加载器的子级。它负责从应用程序类路径加载类。它在内部使用映射到java.class.path的环境变量。它也由sun.misc.Launcher$AppClassLoader班级。
// Java code to demonstrate Class Loader subsystem 
public class Test 
{ 
    public static void main(String[] args) 
    { 
        // String class is loaded by bootstrap loader, and 
        // bootstrap loader is not Java object, hence null 
        System.out.println(String.class.getClassLoader()); 

        // Test class is loaded by Application loader 
        System.out.println(Test.class.getClassLoader()); 
    } 
}     

输出:

null
sun.misc.Launcher$AppClassLoader@73d16e93

注:JVM遵循委托层次原则来加载类。系统类加载器将加载请求委托给扩展类加载器,而扩展类加载器将请求委托给引导类加载器。若在引导路径中找到类,则类被加载,否则请求再次传输到扩展类装入器,然后再传输到系统类装入器。最后,如果系统类加载器未能加载类,那么我们将得到运行时异常java.lang.ClassNotFoundException.

虚拟机

2、JVM内存


Method  Area(方法区域):类的名称、类信息等都是存储在类级的直接变量、类信息等。每个JVM只有一个方法区域,它是一个共享资源

Heap Area(堆区域):所有对象的信息存储在堆区域中。每个区域也有一个JVM堆。它也是一种共享资源

Stack Area(栈区域):对于每个线程,JVM创建一个运行时堆栈,它存储在这里。这个堆栈的每个块称为激活记录/堆栈帧,用于存储方法调用。该方法的所有局部变量都存储在相应的帧中。线程终止后,它的运行时堆栈将被JVM销毁。它不是共享资源

PC Registers(程序寄存器):线程当前执行指令的存储地址。显然每个线程都有独立的PC寄存器,它不是共享资源

Native Method Stacks(本机方法堆栈):对于每个线程,都会创建单独的本机堆栈。它存储本机方法信息,它不是共享资源

jvm2

3、Execution Engine(执行引擎)
执行引擎执行.等级(字节码)。它逐行读取字节码,使用存在于不同内存区的数据和信息并执行指令。它可以分为三个部分:

  • Interpreter(解释器):它逐行解释字节码,然后执行。这里的缺点是当一个方法被多次调用时,每次都需要解释。
  • Just-In-Time(实时编译器JIT):用于提高解释器的效率,它编译整个字节码并将其更改为本机代码,这样每当解释器看到重复的方法调用时,JIT会直接为该部分提供本机代码,因此不需要重新解释,从而提高了效率。
  • Garbage Collector(垃圾收集器):它销毁未引用的对象。有关垃圾回收器的详细信息,请参阅垃圾收集器.

Java Native Interface(Java本机接口JNI):
它提供了一个本机C++库,它提供了一个本机C++执行库。它使JVM可以调用C/C++库,也可以被特定于硬件的C/C++库调用。

Native Method Libraries(本机方法库):
它是执行引擎所需的本机库(C,C++)的集合。

4、JVM简图

原文地址:https://www.cnblogs.com/crelle/p/13676064.html