JVM学习之路4-类文件结构及加载机制

继上一篇JVM学习之路3-GC机制和GC收集器分析介绍完垃圾回收相关内容后,这篇说说类的加载机制。我们平时在写代码的时候更多的是和对象打交道,很少去关心类的相关信息是怎么来的,在之前的系列文章中我们介绍过类信息是存放在哪的、对象是如何找到自己的类等内容,都没有详细介绍过类是如何来的,它是怎么被加载到虚拟机里的。
知识点
1、类文件结构
2、虚拟机加载类机制

类文件结构

这里整理了一幅图先做整体展示
JVM学习之路4-类文件结构及加载机制_第1张图片
上面图已经对各个结构做了简单的说明,字段表集合是不包含方法的局部变量,这里再介绍一下常量池。

常量池

就是指字面量和符号引用,字面量即java语言层的常量概念,符号引用如:类和接口全限定名、字段方法名称和描述符等。每种常量项都有自己的一个表结构,具体可以再看一下书里的表,这里不再做引用。一般java用Constant_utf8_info项来存类名和方法名,所以我们平时定义类和方法的时候不能过长(65535),当然一般也不会那么长。

虚拟机加载类机制

一个类从加载进虚拟机内存到从内存中卸载,整个生命周期如下:
JVM学习之路4-类文件结构及加载机制_第2张图片
加载、验证、准备、初始化、卸载这五个阶段的顺序是确定的,以下6种情况下必须先对类进行初始化:
1、遇到new、getstatic、putstatic、invokestatic指令,基本上就是new对象、静态方法调用和静态字段访问。
2、反射调用。
3、父类没初始化过先做初始化。
4、虚拟机启动时执行主类要先初始化。
5、动态语言最终对应的方法静态调用需要先初始化。
6、有默认方法的接口要在类实例化前进行初始化。

加载

此阶段把类从文件的二进制流转换到方法区的运行时数据结构并生成class对象。除了从.class文件中加载类信息,我们还可以通过网络、zip等压缩包、或者在代码中动态生成类信息。这里需要注意的是:数组类不是由类加载器加载,数组类如果放的是引用类型,该引用类型是由类加载器来加载,该数组类会被标识在该类加载器的类名称空间上,如果数组类放的不是引用类型,则会被标识在引导类加载器上。

验证

这是连接的第一个阶段,主要是为了保证加载的类字节流符合虚拟机规范,防止恶意代码的侵入,保护虚拟机的安全,为什么说java是类型安全的,这部分就是主要原因,主要有如下几部分校验:
1、文件格式校验,比如文件的魔数是否符合定义。
2、元数据校验,对字节码描述的信息进行校验(看字节码:javap -verbose xxxClass),比如是否继承了不被允许继承的类。
3、字节码验证,通过数据流和控制流分析来确保语义是合法的、符合逻辑的。
4、符合引用验证,发生在虚拟机将符号引用转换为直接引用时,比如检查是否缺少依赖的外部方法、类等资源。

准备

正式为类中的变量分配内存和设置初始值。举个例子:

public static int value = 123;

如上代码,在准备阶段的时候会将value设置为0,而不是123,真正赋值123是在初始化阶段。当然如果是常量(用final修饰),则会直接初始化为123。

解析

将常量池中符号引用替换为直接引用的过程,包括类/接口解析、方法解析、字段解析、接口方法解析等。
符号引用:就是一个字面量,比如类的全限定名,只要能唯一识别该类就行,和内存布局无关。
直接引用:和内存布局相关,内存中要已经存在该目标,直接引用相当于直接定位到该目标。

初始化

类加载过程的最后一个步骤,虚拟机将主导权交给应用程序。准备阶段在分配内存和设置初始值之后,初始化阶段就会真正设置我们赋予的初始值,就是在执行类构造器()方法的过程。静态语句块中只能访问 到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。

类加载器

在上面的加载机制中提到了类加载器,它除了可以加载类以外,还可以确认一个类在虚拟机中的唯一性(对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性),同一个类被同一个虚拟机加载,只要加载器不同,那类必定也不同。

双亲委派模式

java虚拟机经典的双亲委派模式。一幅图:
JVM学习之路4-类文件结构及加载机制_第3张图片
启动类加载器(BootstrapClassLoader):负责加载存放在 \lib目录,或者被-Xbootclasspath参数所指定的路径中存放的类到虚拟机中。
扩展类加载器(ExtClassLoader):负责加载\lib\ext目录中,或者被java.ext.dirs系统变量所 指定的路径中所有的类库。
应用程序类加载器(AppClassLoader):负责加载用户类路径 (ClassPath)上所有的类库。
基本机制:每当加载一个类的时候,虚拟机会先用启动类加载器进行加载,加载不到再用扩展类加载器,再加载不到就用应用程序类加载器进行加载。这样可以保证一个类在虚拟机里唯一。

总结

本篇主要介绍了类文件结构以及类加载机制,整个类的加载过程还是比较清晰且简单的,大家也可以自己试着定一个类加载器来加载类,跟进代码看一下双亲委派模式具体怎么走。

你可能感兴趣的:(jvmJVM)