zoukankan      html  css  js  c++  java
  • 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简图

  • 相关阅读:
    计算机世界中解决问题的三种技术手段
    应用程序池的经典模式与集成模式的区别
    sh文件的编译
    flex学习开始了
    com,ActiveX,Ole之间的关系学习总结
    "正在等待localhost。。”问题的解决
    一些感悟
    面向对象软件工程方法学实践【转】
    外连接在sqlserver和access之间的差异
    外连接在sqlserver和access之间的差异
  • 原文地址:https://www.cnblogs.com/crelle/p/13676064.html
Copyright © 2011-2022 走看看