JVM中的类加载机制

一、前言

这篇博客主要总结一下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.接口方法解析


初始化

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

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

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

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

4.虚拟机启动时,优先初始化含main()方法的类。

类加载器

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

双亲委派模型

类加载器从虚拟机的角度讲,一种是启动类加载器,一种是其它所有的类加载器。
先看看下图


双亲委派模型

双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都需要有自身的父类加载器,并且类加载器之间的关系是以组合的关系来复用加载器代码。

工作过程

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

总结

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容