JVM:(一)建立JVM大局观

一、官网眼中的JVM

JVM是JAVA平台基石,负责屏蔽操作系统跟硬件。

JVM是虚拟的计算机,拥有自己的指令集及定义了不同的运行内存来负责虚拟机的运行。

JVM对JAVA的语法不感冒,只在乎class file字节码文件。

JVM能够运行有效的class file的文件,是一个多语言的平台。

上述解释可能太官方了,不一定能理解,我们可以看看下面这张图

在这里插入图片描述
java语言在推行之初就打出了一个口号:Write Once,Run
AnyWhere!
一次编译到处运行。 我们把java的源文件通过javac去编译后会生成对应的字节码文件,我们拿到这个字节码文件或者把若干个字节码文件打成jar包,然后再把源文件或者jar包挪到不同的平台上去执行。

二、jdk、jre、jvm的区别和联系

https://www.cnblogs.com/bingyimeiling/p/10266949.html

在这里插入图片描述

java程序是运行在jvm上的。java可以跨平台(一次编译到处运行)并不是因为jdk,而是因为jvm。即jvm是java跨平台的根本。

三、类的加载过程

要学习和理解JVM,我们首先要对JVM有一个基本的概念,下面这张图应该都能理解。

在这里插入图片描述
我们上面说过,jvm是一个多语言的平台,它不只是java虚拟机,除了java语言它还可以支持其他语言,比如groovy。jvm只关注class字节码文件,不关注语言,只要能把语言解析成符合jvm运行规范的class文件,我们jvm就可以支持运行。

在这里插入图片描述
上面有张图的 xxxx机制 其实就是:类的加载过程

在这里插入图片描述
根据这张图我们可以知道类(class)的加载过程大致分为一下几步:

1. 加载

查找和导入class文件

通过一个类的全限定名获取定义此类的二进制字节流.(从class,jar,网络…)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,并在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口链接。

2. 链接

将加载到JVM中的二进制字节流数据合并到JVM的运行时状态中,这里可进一步细分成三个步骤

(1) 验证

检查class字节码是否符合jvm运行规范,比如是否以cafe babe开头、jdk版本、符号引用等等。

(2) 准备

为类的静态变量分配内存,并将其初始化为默认值。

在这里插入图片描述

(3) 解析:将类中的符号引用转化为直接引用

3. 初始化

初始化是为类的静态变量赋值,然后执行类的静态块。

初始化的详细过程:
如果类还没有被加载和链接,那就先进行加载和链接。
如果类存在父类,并且父类还没有初始化,那就先初始化父类。
如果类中存在静态块,则按照静态块顺序执行。

例子:

public class A {
    public static int ANum = 200;

    static {
        System.out.println(ANum);
    }
}

---------------------------------------

public class B extends A {
    public static int BNum = 100;

    static {
        System.out.println(BNum);
    }

    public static void main(String[] args) {
        new B();
    }
}

运行main方法,结果:

在这里插入图片描述

上面说了初始化是为类的静态变量赋值,准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后进行准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析,到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。

四、什么场景会触发class的初始化:

1.创建类的实例(四种方式)
new、clone、序列化、反射
2.访问某个类或接口的静态变量,或者对该静态变量赋值
3.主动调用类的静态方法
4.Class.forName(“包类名”)
5.初始化一个类的子类
6.该类是程序引导入口(例如main入口或者test入口)

五、类加载器ClassLoader

类的加载过程我们已经说过了,那么谁去实现这个流程? 他就是类加载器,即类加载器是类加载流程的实现者。

JDK自带的Class Loader:

  1. 根类加载器(Bootstrap ClassLoader)
    (1)它用来加载 Java 的核心类库,是用C/C++来实现的,并不继承自 java.lang.ClassLoader,打印为null。由于它涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。
    (2)它负责加载$JAVA_HOME中jre/lib/rt.jar、resouce.jar或Java程序运行时指定的-Xbootclasspath参数下的jar包。
    (3)Bootstrap只加载包名为java、javax、sun等开头的类。
  2. 扩展类加载器(Extension ClassLoader)
    (1)由Java语言实现,是java.lang.ClassLoader类的子类,是Launcher的内部静态类(ExtClassLoader),父加载器是Bootstrap ClassLoader。
    (2)它负责加载JRE的扩展目录,即$JAVA_HOME中jre/lib/ext或者由-Djava.ext.dirs指定目录下的jar包。
  3. 系统类加载器(System ClassLoader)
    (1)由Java语言实现,是java.lang.ClassLoader类的子类,是Launcher的内部静态类(AppClassLoader),父加载器是Extension ClassLoader。
    (2)该加载器是Java程序的默认加载器,java应用的类都是该类加载器加载的,它负责加载环境变量classpath指定的目录或者-Djava.class.path指定的目录的类库。

我们大致验证一下,是不是如我们上述说的一样:

在这里插入图片描述
Test.class是java应用程序的类,即我们自己创建的类,它由我们AppClassLoader加载,它的父类则是ExtClassLoader,父类的父类是Bootstrap ClassLoader则打印为空。String.class由Bootstrap ClassLoader加载,打印为空。

六、双亲委派加载机制

上面说了类加载器负责实现类的加载过程,那为什么需要分这么多个Class Loader?

先说结果:最主要的目的就是为了实现双亲委派加载机制

1. 原理

在这里插入图片描述
双亲委派机制,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成。

2. 优势

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改

3. 源码

上面说了什么是双亲委派机制,以及为什么使用双亲委派机制。具体的实现对应的其实是ClassLoader.class中的protected Class<?> loadClass(String name, boolean resolve),实现细节可以参考下面核心方法源码和双亲委派的流程图然后自行百度。

在这里插入图片描述
参考文章:https://blog.csdn.net/briblue/article/details/54973413

七、总结

看下图对整个jvm有个全局的认识,这篇只说了这张图的一小部分,后面几篇文章会去慢慢分析这张图。
在这里插入图片描述

下一篇:JVM:(二)JVM运行时数据区

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值