浅谈Java虚拟机

每一个java程序员在自己的电脑上都会装jdk,而jdk中包含了编译、运行等开发工具和JRE,而JRE中包含了java的系统类库和JVM(java虚拟机),如图

而我们写的java程序都会交给jvm去执行,那什么又是jvm呢? 由于知识有限,有不对的地方,请各位同行批评,斧正。

有些时间不是很足的同学可以直接跳过中间的内容,直接看下面的总结部分。

我们先在网上看一下对虚拟机比较靠谱的解释:

虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器堆栈寄存器等,还具有相应的指令系统JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就是.class文件,就可以在多种平台上不加修改地运行。

通俗点来讲:就是java虚拟机有自己的一套运行架构,用来运行.java文件所编译后的.class字节码文件的一个抽象化计算机。而"JVM屏蔽了与具体操作系统平台相关的信息",就说明了java程序经过编译之后,无论你是什么平台,什么系统,只要你装了java虚拟机,都可以运行,这就是使得java这门语言可以跨平台使用。只是由于系统的不同,JVM也不同罢了。但是其实现的步骤是一样的。

我们从进程的角度来理解一下JVM:

 我们都知道,虚拟机是运行在操作系统中的,那么又是什么东西才能在操作系统中运行呢?没错,就是“进程”,因为进程是操作系统中最基本的执行单位。当它再运行的时候,它就是一个操作系统中的进程实例,当它没有运行的时候,我们可以将其称作为程序。如果说QQ,当QQ运行起来的时候,在任务管理器中,QQ就会是一个进程实例,当QQ没有运行的时候,它就是作为一个QQ.exe存放在文件系统中的。

 熟知命令行的程序员都知道,其实一个命令对应一个可执行的二进制文件,当执行这个命令的时候,就会创建一个进程,加载对应的可执行文件到进程的地址空间中,并且执行其中的指令。

我们看一下java的helloworld程序的编译和执行:

helloworld.java

public class HelloWorld {

public static void main(String[] args) {

System.out.println("HelloWorld");

}

}

然后这个.java程序经过javac编译之后,就会生成一个helloworld.class的字节码文件。

然后经过java命令运行这个.class字节码文件,就会输出HelloWorld。

从这个过程可以看出,我们在运行java程序的时候,我们是要先要将.java的文件编译成.class字节码文件,然后经过java命令来执行这个.class字节码文件。因为.class文件并不能直接被操作系统识别的二进制可执行文件。我们用的java这个命令说明,我们首先是启动了一个叫做java的程序,这个java程序在运行起来之后就是一个JVM的进程实例。

命令执行流程是这样的:

java命令首先启动虚拟机的进程,虚拟机进程成功启动之后,然后读取参数"HelloWorld",把他作为初始类加载到内存中,对这个类进行初始化动态链接,然后从类的main方法开始执行。也就是说我们的.class字节码文件并不是直接被系统加载后直接在cpu上执行的,而是被一个叫做虚拟机的进程托管的。首先必须要让虚拟机进程启动就绪,然后由虚拟机中的类加载器加载必要的class文件,包括jdk中的基础类,然后由虚拟机进程执行class字节码指令,把这些字节码指令翻译成本机cpu能够识别的指令,这样才能在cpu上去运行。

所以从这个层面上来看的话,在执行一个.java程序的时候,真正执行的是JVM进程,而不是.class字节码文件。这个JVM进程处理一些底层的操作,比如内存的分配和释放等。虚拟机进程执行的是我们的.class字节码文件,这些文件在运行时,会被加载到虚拟机中,被虚拟机解释执行,以控制虚拟机实现我们java代码中一些操作。比如I/O流创建一个文件等等,可以将class文件中的信息看做对虚拟机的控制信息,也就是一种虚拟命令。

JVM体系结构:

如图:


一:类加载子系统

我们编译过后的class文件是作为JVM的一种"原料"被输入到虚拟机的内部中去的,而负责这一部分工作的,其实是在JVM内部中有一个叫做类加载器子系统,这个子系统用来在运行时根据需要加载类。意思就是,在JVM执行过程中,只有当它需要一个类的时候,才会去调用这个类加载器去加载这个类,并不会一开始就去加载所有的类。意思就是JVM在执行的时候,当程序需要调用一个A类的时候,类加载器才会去调用这个A类,并不会一开始执行的时候就会把A、B、C...Z类全部都加载出来,那工作量的大了去了。一般来说,虚拟机加载类的时机,是在第一次使用一个新的类的时候加载。

二:执行引擎子系统

由虚拟机加载的类,被加载到JVM的内存中之后,虚拟机会读取并执行它里面存在的字节码指令,虚拟机中执行字节码指令的部分叫做执行引擎子系统。执行引擎的作用之一就是把各个class文件动态的连接起来。

三:垃圾回收子系统

java和其他语言有一个最大的不同,也是其特色之一,就是GC,垃圾回收机制。JVM会进行自动内存管理,具体来说就是自动释放没有用的对象,而不需要程序员编写代码去手动释放资源。这部分工作就是由JVM中的垃圾收集子系统来负责的。

所以,综上所诉,一个JVM实例在运行过程中有三个子系统来保障它能正常运行。如图:


虚拟机的运行,必须加载class字节码文件,并且执行该文件中的字节码指令。那么它做这么多的事情,肯定会需要它自己的一个空间,也就是说虚拟机需要空间来存放数据。

它加载的字节码需要一个单的内存空间来存放,一个线程的执行,也需要内存空间来维护方法的调用关系,存放方法中的数据和中间计算结果等等等等。虚拟机在运行时内存区大概可以分成几个部分(大致表示一下),如图:


总结:

写在这里也写的差不多了,由于自己水平有限,也只能这样了,如果想要更加深入的了解JVM的知识,强烈推荐:

《深入Java虚拟机》

《深入理解Java虚拟机JVM高级特性与最佳实践》

Java虚拟机规范》


对以上的内容做一个总结:

1.JVM(java虚拟机)从操作系统的角度来看,就是一个普通的进程

2.这个虚拟机的进程较为特殊,它能够加载.class字节码文件。如果把JVM比作一辆车,那么class字节码文件就是油(气、电);

3.加载class字节码文件的是一个叫做类加载器的子系统。就好比汽车的油箱口,将油送达至油箱中;

4.JVM中的执行引擎子系统是用来执行class文件中的字节码指令。就好比汽车的发动机,对油箱中的油进行燃烧处理。

5.JVM在执行过程中,要分配内存创建对象,当这些对象过时无用了,必须要自动清理这些无用的对象。垃圾回收机制(GC)就是由垃圾收集器子系统来负责的。就好比汽车发动机将汽油燃烧后,排出废气,腾出空间燃烧下一次的汽油。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值