JVM中的类加载机制

原创 2018年04月15日 16:32:55

一、前言

这篇博客主要总结一下Java虚拟机中的类加载机制,刚开始学习Java时,相信大多数人第一步都是使用的java c的命令去编译.Java的文件,编译后产生了一个class文件,而类文件又是被JVM进行怎样的操作才能运行?读完这篇博客,相信你能有一个整体的了解。

二、加载过程概述

类从被加载到虚拟机的内存开始一直到被卸载出内存,生命周期一共包括了:加载、验证、准备、解析、初始化、使用、卸载7个阶段。如下图所示
生命周期
其中验证、准备、解析统称为连接阶段,这里来一一介绍加载过程中每个阶段需要进行的操作。

加载

这个阶段,需要完成以下三件事:
1.通过一个类的全限定名(绝对路径)来获取定义此类的二进制流。
2.将这个字节流所代表的静态存储结构转化为方法区运行时的数据结构。
3.在内存中生成一个代表此类的java.lang.Class对象,作为方法区该类的各种数据的访问接口。
对Java内存区域不太了解的可以去看看我前面一篇博客Java内存区域
这里由第一点,可以看出获取类的二进制流可以有多种不同的途径,正是如此,Java虚拟机给开发人员提高了很大的扩展性。这里注意,数组类不通过加载器创建,而是由Java虚拟机直接创建,但是数组的元素类型(去除维度后)最终还是由类加载器去加载。
加载阶段完成后,就开始连接阶段,注意加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证操作)是交叉进行的,接下来就介绍一下连接阶段。


验证

验证阶段是连接的第一步,这一步目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求。验证阶段要遵循的具体规范比较多,这里没必要写出来了,有兴趣的朋友可以去JVM的官网去看,这里重点是大体上了解整个流程。整体上看。验证阶段分为以下几个步骤:

1.文件格式验证

2.元数据验证

3.字节码验证

4.符号引用验证

准备

准备阶段是正式为类变量分配内存并设置变量初始值的阶段,这里注意一下,这个初始值不是开发人员给某个变量赋的值,而是不同的类型对应的“零值”。这些变量所使用的内存都将在方法区中进行分配,这时候进行内存分配的变量仅仅包括类变量(被static修饰的变量),实例变量将会在对象实例化时随着对象一起分配在Java堆中。

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,这里还是先来简单的介绍一下符号引用于直接引用。
符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量(如我们常说的变量名),只要准确无误的能定位到目标就可以,与虚拟机的内存布局无关。
直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄,与虚拟机的内存布局相关。
因为在程序中对同一个符号引用进行多次解析请求是常见的,所以虚拟机实现了对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并且把常量标识为已解析状态)。这里也是,具体的解析规范不多写,具体解析的步骤如下:

1.类或接口的解析

2.字段解析

3.类方法解析

4.接口方法解析


初始化

该阶段是类加载过程中的最后一步,前面的类加载过程中,除了开发人员可以通过自定义类加载器参与加载阶段外,其余动作都是都是完全由虚拟机主导和控制,到了这个阶段,才真正开始执行类中的程序代码。
之前在准备阶段,变量已经赋过一次初始值,而初始化阶段将根据开发人员定义的去进行赋值,换个角度看,初始化阶段是执行类构造器()方法的过程。接下来就来详细的介绍一下该方法。

1.()方法是由编译器自动收集类中的所有变量的赋值动作和static语句块中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定的,并且金静态语句块只能访问到定义在静态语句块之前的变量。
2.()方法与类的构造方法不同,不需要显示的调用父类构造器,但虚拟机会保证在子类的()方法执行之前,父类的该方法已经执行完,所以第一个被执行的该方法肯定是Object类。
3.如果一个类中没有静态语句块,也没有变量的赋值操作,编译器可以不为这个类生成()方法。这里注意,执行接口的()方法不需要先执行父接口的该方法,并且接口的实现类在初始化时也不会执行接口的该方法。
4.虚拟机保证一个类的()方法在多线程环境中被正确的加锁、同步,并且通一个类加载器下,一个类型只会初始化一次。

初始化时,虚拟机还要遵守几条必须立即对类进行初始化的规范规范,也就是对类进行主动引用

1.使用new关键字实例化对象、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外),以及调用一个类的静态方法的时候,类没有进行过初始化,则需要触发其初始化。
2.对类进行反射调用的时候。
3.初始化一个类时,其父类还没被初始化,则需要先触发其父类的初始化。
4.虚拟机启动时,优先初始化含main()方法的类。

类加载器

前面也多次提到了类加载器,这里来专门总结一下相关的知识,每一个类加载器都拥有一个独立的类名称空间,所以比较两个类是否相等,首先要比较的不是类名,而是是否来自同一个类加载器。说到类加载器。就离不开类加载器之间的关系模型。

双亲委派模型

类加载器从虚拟机的角度讲,一种是启动类加载器,一种是其它所有的类加载器。
先看看下图
双亲委派模型
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都需要有自身的父类加载器,并且类加载器之间的关系是以组合的关系来复用加载器代码。

工作过程

如果一个类的加载器收到了类加载的请求,首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,层层递进,因此所有的加载请求最终都被传送的顶层的启动类加载器中,只有当父类加载器无法完成请求时,子加载器才会自己去进行下载。
可以看出,双亲委派模型保证了Java程序的稳定运作,不会因为混乱的加载方式使程序无法正常加载运行。
最后说一下,现在很多的新技术都不是双亲委派模型中的树状结构,而是发展为更复杂的网状结构,这里还了解的不够多,就不必多说了。

总结

这篇博客系统的总结了一下JVM中的类加载机制,但更多的细节还是没有讲明,有兴趣了解更多的朋友的还是去读读《深入理解JVM虚拟机》,就暂时到这里了。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/github_36498175/article/details/79950459

JVM(四)—一道面试题搞懂JVM类加载机制

有这样一道面试题: class Singleton{ private static Singleton singleton = new Singleton(); public s...
  • noaman_wgs
  • noaman_wgs
  • 2017-07-05 19:35:20
  • 2757

【深入理解JVM】:类加载机制

概述虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。与那些在编译时需要进行链接工作的语言不同,...
  • u011080472
  • u011080472
  • 2016-05-06 10:13:25
  • 3682

深入JVM类加载机制

类加载的流程以及双亲委派模型
  • dd864140130
  • dd864140130
  • 2015-11-13 14:13:19
  • 5344

jvm 类加载机制 双亲委派模型

  • 2018年04月17日 10:13
  • 359KB
  • 下载

【深入Java虚拟机】之四:类加载机制

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。 其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这...
  • mmc_maodun
  • mmc_maodun
  • 2014-01-08 00:09:27
  • 45621

jvm笔记5--虚拟机类加载机制

前言: 虚拟机将描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,及为虚拟机类加载机制。 在Java语言中,类型的加载,连接和...
  • panningwjr
  • panningwjr
  • 2016-09-26 14:07:11
  • 2438

Java进阶(五十四)初识JAVA类加载机制

Java进阶(五十四)初识JAVA类加载机制  什么是类加载呢?当我们写完一个Java类的时候,并不是直接就可以运行的,它还要编译成.class文件,再由虚拟机解释给当前的操作系统去执行。这些过程都是...
  • sunhuaqiang1
  • sunhuaqiang1
  • 2017-02-28 19:36:05
  • 43216

java内存模型与类加载机制

Java内存模型,是指多线程并发时,将内存分为主内存和工作内存,每条线程运行时拥有自己的内存区域。 Java内存模型主要从三个特性进行解释。 一是原子性,线程工作时,一共八个原子操作,...
  • dragon_cat_han
  • dragon_cat_han
  • 2016-08-08 13:06:57
  • 1816

JVM(三):类加载机制(类加载过程和类加载器)

使用java编译器可以把java代码编译为存储字节码的Class文件,使用其他语言的编译器一样可以把程序代码翻译成Class文件,java虚拟机不关心Class的来源是何种语言。如图所示: 在Cla...
  • boyupeng
  • boyupeng
  • 2015-08-25 15:38:32
  • 22725

【Java面试整理之JVM】深入理解JVM结构、类加载机制、垃圾回收GC原理、JVM内存分配策略、JVM内存泄露和溢出

一、前言最近要准备找工作,JVM肯定是跑不掉的面试内容,所以把JVM相关的内容拿来认真学习一遍,整理成自己能够快速消化的提纲,方便随时可以调用。主要分JVM结构、类加载机制、垃圾回收GC原理、JVM内...
  • shengmingqijiquan
  • shengmingqijiquan
  • 2017-08-23 17:11:40
  • 734
收藏助手
不良信息举报
您举报文章:JVM中的类加载机制
举报原因:
原因补充:

(最多只允许输入30个字)