到底什么是Java虚拟机
1、何为Java虚拟机:
作为一名不是很合格的java程序员,我们每天都在写java代码,我们写好的java代码都是在一个叫做java虚拟机的东西上运行的,那什么是java虚拟机呢? 估计很少有人能够解释的清楚;
先来看下网上对java虚拟机的解释:
虚拟机是一种抽象化的计算机,通过在现实中的计算机上仿真模拟各种计算机功能来实现。Java虚拟机有自己完善的硬体架构如:处理器、堆、栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(.class 字节码),就可以在多种平台上不加修改的运行,这也就实现了:一次编译 处处运行了。
以上的解释应该是比较全面的,但是只描述了虚拟机的外部行为和功能,并没有对内部原理做出说明。一般情况下我们不需要知道虚拟机的运行原理,当然了如果知道的话那就更有利于我们的理解了,我们只需要专注的写我们的java代码就可以了。
2、从进程的角度来解释 JVM:
我们尝试从操作系统的层面来理解虚拟机,我们知道虚拟机是运行在操作系统之中的,那么什么东西才可以运行在操作系统之中呢? 答案是:进程 因为进程是操作系统中的执行单位,可以这样理解,当 进程
运行的时候,它就是操作系统中的进程实例,没有运行时(作为可执行文件存放于文件系统中),可把它叫做程序。
玩过命令的同学都知道我们平时用到的命令其实就是一个个的可执行文件,当敲入一个命令并回车后,就会创建一个进程并加载对应的可执行文件到进程的空间地址中,并且执行其中的命令。
Java语言的HelloWorld程序来说明问题。
public class HelloWorld{
public static void main (Strings[] args) {
System.out.println("HelloWorld");
}
}
使用命名 javac
来编译HelloWorld程序,编译完成后在原来的目录中就会多出一个 HelloWorld.class 文件;
使用命令 java
来执行该字节码文件;
注意:
.class文件并不是一个可以直接被操作系统识别的二进制文件,java
这个命令说明我们首先启动的是一个叫做java的程序,而这个java程序运行起来之后就是一个 JVM
进程实例。
命令执行的流程如下:
java
这个命令首先启动 JVM 进程,JVM 进程启动成功后,读取参数 “HelloWorld”,把它作为初始类加载到内存,对这个类进行初始化和动态链接,然后从类 HelloWorld 的main 方法开始执行,也就是说 .class 文件不是直接被系统加载后直接在 cpu 上执行的,而是被一个叫做虚拟机的进程托管的。首先必须 JVM进程启动完成,然后由 JVM 中的类加载器加载必要的 class 文件,包括 JDK 的一些基础类如:Object、String等,然后由 JVM 进程解释 class 字节码指令,把这些指令翻译成本机 cpu 可以识别的指令,才能在 cpu 上运行。
在执行一个所谓的 java 程序的时候,其实执行的是一个叫做 java虚拟机的进程,而不是我们写的经过编译后的一个个的 .class 字节码文件,这个叫做虚拟机的进程处理一些底层操作,比如内存的分配和释放等等,class文件只是虚拟机进程执行时需要的“原料”。这些"原料"运行时被加载到虚拟机中,然后被虚拟机解释执行,以控制虚拟机实现我们java代码中的定义的一些高级操作,如创建一个文件等,可以将class文件中的信息看做对虚拟机的控制信息,也就是一种虚拟指令。
JVM 体系结构简介:
编译之后的class文件是作为java虚拟机的"原料"被输入到Java虚拟机的内部的,那么具体由谁来做这一部分工作呢? 其实在JAVA虚拟机的内部,有一个叫做类加载器的子系统,这个子系统用来在运行时根据需要加载类。在Java虚拟机执行过程中,只要当需要一个类的时候,才会调用类加载器来加载一个类,并不会在开始的时候就把全部的类加载完。就像是一个人只有在感觉憋的慌的时候才去上厕所,而不是一次把一周的尿全撒完(哈哈~)。
虚拟机加载类,被加载到虚拟机内存之中,虚拟机会读取并执行其里面的字节码指令。虚拟机中执行字节码指令的部分叫做执行引擎。就像是一个人,不是说把饭吃下去就完事了,还要进行消化, 执行引擎就相当于人的肠胃系统。在执行的过程中还会把各个class文件动态的连接起来。
Java虚拟机会进行自动内存管理,就是自动释放掉没有被引用的对象,而不需要我们手动编写代码来释放分配的内存,这部分的工作是由垃圾收集子系统来负责。
从上面的论述我们知道,一个Java虚拟机实例在运行过程中有三个子系统来保障它的正常运行,分别是:
- 类加载器子系统
- 执行引擎子系统
- 垃圾收集子系统
虚拟机的运行必须要加载class文件,并且执行class中的字节码指令,它做这么多事,必须要有自己的空间,就像人吃了东西首先要放在胃中。虚拟机也需要空间来存放这些数据。首先加载的字节码需要一个单独的空间来存放;一个线程的执行,也需要内存空间来维护方法的调用关系,存放方法中的数据和中间计算结果;在执行的过程中,一定会要创建对象, 创建的对象需要一个专门的内存空间来存放 。
虚拟机的运行时内存区大概可以分成下图所示的几个部分。(这里只是大概划分, 并没有划分的很精细)
该博主写的很好,强力推荐,值得我这样的小白学习;