JVM(Java Virtual Machine,Java 虚拟机)。它是一个虚构出来的计算机,是一种规范。通过在实际的计算机上仿真模拟各类计算机功能实现,也可以理解为 JVM 就类似于一台小电脑运行在 Windows 或者 Linux 这些操作系统环境下,直接与操作系统进行交互,与硬件不进行直接交互,操作系统可以帮助 JVM 完成与硬件交互的工作。

java VM 版本 java.vm是什么文件_java VM 版本

之前说过,JVM 是用来运行 java 字节码文件的。那么 Java 文件到底是如何被运行的呢?

比如说我们现在写了一个 HelloWorld.java 文件,抛开相关 Java 的知识不谈,其实这个 .java 文件就是一个普通的文本文件。但是此时 JVM 是不认识这种文本文件的,需要将此 .java 文件编译一下,变成 .class 文件即可,可以使用

javac HellWorld.java

命令来完成编译工作。具体可参考:JDK、JRE、JVM_ 

当编译成一个 .class 文件之后,JVM 就会认识这个文件了。涉及到相关概念为:

类加载器

如果 JVM 要想执行这个 .class 文件,那么就需要将这个文件装进一个类加载器中。类加载器就像一个搬运工一样,会把所有的 .class 文件全部搬进 JVM 里面来。

java VM 版本 java.vm是什么文件_JVM_02

方法区

方法区是用于存放类似于元数据信息方面的数据的,比如说类信息、常量、静态变量、变异后代码等,类加载器将 .class 文件搬过来就是先丢到这一块上。

堆主要存放了一些存储的数据,比如说对象实例、数组等。堆和方法区都同属于线程共享区域。也就是说他们都是线程不安全的。

栈,是代码运行空间,我们编写的每一个方法都会放到栈里面运行。

程序计数器

程序计数器主要是完成一个加载工作,类似于一个指针一样的,指向下一行我们需要执行的代码。和栈一样,都是线程独享的,就是说每一个线程都会有自己对应的一块区域而不会存在兵法和多线程的问题。

java VM 版本 java.vm是什么文件_java_03

总结来说就是:Java 文件经过编译之后变成 .class 字节码文件;字节码文件会通过类加载器被搬运到 JVM 虚拟机中;虚拟机主要有五块区域。方法区、堆区都为线程共享区域,存在线程安全问题,栈区和本地方法栈区以及程序计数器区都是独享区域,不存在线程安全问题,而 JVM 的调优主要就是围绕堆区和栈区两大块进行。

代码示例

public class Student {

    private String name;

    public Student(String name) {
        this.name = name;
    }

    public void print() {
        System.out.println(name);
    }

}


public class HelloWorld {

    public static void main(String[] args) {
        Student student = new Student("HelloWorld");
        student.print();
    }

}

执行 main 方法的步骤如下:

1.编译好 HelloWorld.java 后得到 HelloWorld.class,然后执行 HelloWorld.class,系统会启动一个 JVM 进程,从 classpath 路径中找到一个名为 HelloWorld.class 的二进制文件,将 HelloWorld 的类信息加载到运行时数据区的方法区内,这个过程叫做 HelloWorld 类的加载;

2.JVM 找到 HelloWorld 的主程序入口,执行 main 方法;

3.这个 main 方法中的第一条语句为 Student student = new Student("HelloWorld") ,就是让 JVM 创建一个 Student 对象,但是这个时候方法区中是没有 Student 类的信息的,所以 JVM 马上加载 Student 类,把 Student 类的信息放到方法区中;

4.加载完 Student 类后,JVM 会在堆中为一个新的 Student 实例分配内存,然后调用构造函数初始化 Student 实例,这个 Student 实例持有指向方法区中的 Student 类的类型信息的引用;

5.执行 student.print(); 时,JVM 根据 student 的引用找到 student 对象,然后根据 student 对象持有的引用定位到方法区中 student 类的类型信息的方法表,获得 print() 的字节码地址;

6.执行 print()

其实只需要知道对象实例初始化时会去方法区中找类信息,完成后再到栈区去运行方法,找方法就在方法表中找。