1:从操作系统的角度来看,虚拟机是一个进程,该进程的实质是一个虚拟的
抽象的计算机,用来将屏蔽与具体操作系统平台相关的信息,主要目的是为了实现java的可移植性。
2:虚拟机用来加载我们编写的class文件,class文件对于虚拟机来说,相当于虚拟机的原料,这些“原料”在运行时被加载到虚拟机中,被虚拟机解释执行,以控制虚拟机实现我们java代码中所定义的一些相对高层的操作,比如创建一个文件等,可以将class文件中的信息看做对虚拟机的控制信息,也就是一种虚拟指令。
jvm有三个子系统: 类加载器子系统;执行引擎子系统;垃圾收集子系统
类加载器实现的功能:在jvm运行时根据需要加载类,在jvm的运行过程中,只有当他需要一个类的时候,才会调用类加载器来加载这个类,不会一次加载完所有的类,一般来说,虚拟机加载类的时机,在第一次使用一个新类的时候。
执行引擎子系统的功能:该子系统用来读取被jvm加载的类的字节码指令,也就是说,执行引擎用来执行字节码指令,可以将其理解为把原料,也就是class文件消化掉,在执行的过程中还会把各个class文件动态的连接起来
垃圾收集子系统:Java虚拟机会进行自动内存管理
。具体说来就是自动释放没有用的对象,而不需要程序员编写代码来释放分配的内存。这部分工作由垃圾收集子系统负责。
虚拟机在运行时,首先加载class文件,并且执行class文件中的字节码指令,在此过程中类加载器和执行引擎工作,类加载器加载需要的类,执行引擎读取并执行字节码指令,把这些字节码指令翻译成本机cpu能够识别的指令,在cpu上运行,得出运行结果。同时要注意,虚拟机在运行过程中需要空间来存放各类数据,首先,加载的字节码,需要一个单独的内存空间来存放;一个线程的执行,也需要内存空间来维护方法的调用关系,存放方法中的数据和中间计算结果;在执行的过程中,无法避免的要创建对象,创建的对象需要一个专门的内存空间来存放。
上图为简略的jvm运行时的内存区划分示意图
以经典且简单的“hello,word"程序为例,分析虚拟机的运行过程
public class HelloWorld {
public static void main(String[] args) {
System.out.println("HelloWorld");
}
}
运行Java版的HelloWorld程序:
117190@DESKTOP:/deve/workspace/HelloJava/src$ java -classpath . HelloWorld
从上面的过程可以看到, 我们在运行Java版的HelloWorld程序的时候, 敲入的命令并不是 ./HelloWorld.class 。 因为class文件并不是可以直接被操作系统识别的二进制可执行文件 。 我们敲入的是java这个命令。 这个命令说明, 我们首先启动的是一个叫做java的程序, 这个java程序在运行起来之后就是一个JVM进程实例。
上面的命令执行流程是这样的:
java命令首先启动虚拟机进程,虚拟机进程成功启动后,读取参数“HelloWorld”,把他作为初始类加载到内存,对这个类进行初始化和动态链接,然后从这个类的main方法开始执行。也就是说我们的.class文件不是直接被系统加载后直接在cpu上执行的,而是被一个叫做虚拟机的进程托管的。首先必须虚拟机进程启动就绪,然后由虚拟机中的类加载器加载必要的class文件,包括jdk中的基础类(如String和Object等),然后由虚拟机进程解释class字节码指令,把这些字节码指令翻译成本机cpu能够识别的指令,才能在cpu上运行。
从这个层面上来看,在执行一个所谓的java程序的时候,真真正正在执行的是一个叫做Java虚拟机的进程,而不是我们写的一个个的class文件。这个叫做虚拟机的进程处理一些底层的操作,比如内存的分配和释放等等。