深入理解JVM类加载流程

类加载器基本概念

顾名思义,类加载器就是用来加载Java类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:

.java文件在经过编译器编译后转换成字节码的.class文件。类加载器负责读取.class文件并转换成 Class 类的一个实例。每个这样的实例用来表示一个 Java 类,通过new 或 类的newInstance 就可以创建出该类的对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的

Java的类加载流程

java的类加载步骤为:加载- > 连接(验证,准备,解析)-> 初始化

注:其中的流程并不是严格的先后顺序,比如在加载时,可能就开始验证了,是交替运行的

加载

加载就是将编译后的.class文件读取到内存中的方法区中,然后暴露给程序进行访问。

通过类的全限定名来获取到类的二进制字节流(可以是.class文件,也可以是网络上的文件等)。

连接

验证

由于加载阶段加载的不一定全部是.class文件,还有可能是一些网络资源,所以JVM为了自身的安全,要先对文件格式进行校验。

准备

扫描二维码关注公众号,回复: 11462062 查看本文章

准备阶段中主要是给static变量分配内存,并为变量设置初始值;

public static int num = 1; 在准备阶段的值为0。

public static final int num = 1; 此类常量是在准备阶段赋值的。

解析

解析阶段有两个概念:符号引用,直接引用

我们编写的本地代码在进行编译成.class文件后,方法之间调用的关系通过字节码的形式存在,这就是符号引用;

而在JVM将类加载到内存中后,方法之间要互相调用就要通过对象的地址,这就是一种直接引用;

而在解析阶段做的事情就是将.class文件中的符号引用转换成直接引用

初始化

初始化阶段会调用类的静态代码块和为static静态变量赋初始值。

注:一个类可以多线程并发执行,JVM会通过加锁保证单一性,所以不要再static代码块中做一些耗时操作,否则会引起线程阻塞;

使用

使用就是可以直接new出对象或通过反射的newInstance获取到类的实例,然后进行一些操作。

执行编译JIT

JIT(Just in time)运行时编译,将Java字节码重新编译优化,生成机器码,让CPU直接执行,这样编译出来的代码效率更高一些,通常我们不会将所有的Java方法都编译成机器码,主需要将调用最频繁,占据CPU时间最长的方法找出来,提前编译成机器码,这种方法就是热点方法。这种运行时按需编译的方式就是JIT

不同于C、C++语言将程序直接翻译成机器指令执行,java是通过javac 将.java源文件编译成.class文件。JVM在加载了这些class文件后,针对字节码逐条取出然后逐条的执行,这种方式就成为解释执行;

JIT的实现方式就是申请一块有写权限和执行权限的内存,将编译的Java方法编译成机器码,提前写入到内存中,当在需要调用该方法时,就转向调用这块内存。

类加载器 & 双亲委派

深入理解Java的类加载器及双亲委派机制

猜你喜欢

转载自juejin.im/post/5f2042abe51d45346c512525