【类加载机制】从一道面试题开始

0x01.某厂面试题

请阐述Java自带哪些加载器以及对应的职责?

(1)Bootstrap ClassLoader(启动类加载器):负责加载<JAVA_HOME>\lib目录,或-Xbootclasspath指定目录下的jar。
特殊说明:JVM认为合理的jar文件名才会被加载,例如:rt.jar、tools.jar,文件名不符合的jar即使放在上述目录下也不会被加载。

(2)Extension ClassLoader(扩展类加载器):负责加载<JAVA_HOME>\lib\ext目录,或java.ext.dirs指定目录下的jar。
特殊说明:Java9以后引入了模块化机制,此加载器被此机制取代。

(3)Application ClassLoader(应用程序类加载器):负责加载用户类路径(ClassPath)上的jar包。

此题出处:周志明的《深入理解Java虚拟机》-7.4.类加载器,变形题很多:
例如:请你选出哪些不是Java自带的类加载器;
例如:给出各类类加载器的描述、职责,选错误的;
例如:将上述类加载器的特殊说明作为干扰选项;——这种题可以无情坑杀很多程序猿...

0x02.不要背,要理解

至此,我们似乎没必要大费周章地解读这样一道记忆题。背下来不就可以了吗?笔者认为不是:
发展24年的Java及JVM,历经若干版本的商业斗争(A new future for Java),衍生出若干语(语)言(法)特(陷)性(阱)。
"背下来就行"的前提有二,可惜对于Java这些语(语)言(法)特(陷)性(阱)都不成立:

(1)知识输入是无二义性的、与时俱进的。
(2)知识输入是有限集。

所以,笔者坚定的认为唯Java程序员最有资格喊出"我秃了,我也变强了"。
所以,笔者坚定的认为唯"深刻理解JVM"(即,深刻理解语法特性到JVM层,甚至操作系统层),是Java程序员的最有效的防秃良药。

0x03.从韩国星工厂看类加载机制的全貌

From《深入理解Java虚拟机》-周志明

Java虚拟机将描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终变成被虚拟机可以直接使用的Java类型,这个过程被称作Java虚拟机的类加载机制......与那些在编译时需要进行连接的语言不同,在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的......用户可以通过Java预置的或自定义类加载器...作为其程序代码的一部分。

从这段经典且严谨的描述,我们可以抽象8个问题,以此宏观地获得类加载机制的全貌:

问题1:加载什么?
问题2:加载得到了什么?
问题3:从哪里加载?
问题4:加载到哪里去?
问题5:何时加载?
问题6:加载流程有几步?
问题7:加载流程如何实现?
问题8:类加载器的约束?

(1)加载什么?

我们在.java文件中编写了一堆代码,被转换成字节码(.class文件),JVM加载就是这个字节码
这个字节码描述的信息[1]包括(但不限于):

有哪些类、哪些接口;
每个类有哪些属性、行为;
类和类的关系;
...

这些信息就是程序员定义的"模板",在程序运行时,当需要基于类A创建实例对象a时,JVM就要先找到类A对应的"模板"。

这些"模板",就像韩国星工场包装女团时的"剧本",每个女星都是基于某个"模板"创建的实例对象,女星的身高、体重、才艺就是"模板"中描述的"属性、行为"。


[1]:本文聚焦类加载机制的全貌,以后再其他文章展开

(2)加载得到了什么?

字节码加载到内存后得到的信息内容还是(1)中提到的字节码中包含的信息,但信息形式变了,抽象、简单地理解为JVM能认识的数据结构[2]

这就像娱乐公司的策划团队在电脑上写好了女团出道的"剧本",女团的经纪人要无差错地仔细阅读"剧本"的电子件,把"剧本"存储在大脑中,以备后续使用。


[2]:本文聚焦类加载机制的全貌,以后再其他文章展开

(3)从哪里加载?

用一张表,说明字节码文件与经纪人的类比关系:

字节码文件在哪里? 剧本在哪里?
在本地磁盘上,JVM在指定目录去查找 在电脑上,经纪人去指定目录去打开看
在网络上,JVM在指定网络路径上去查找 在某个网站上,经纪人去这个网站上看
JVM根据某些规则动态生成 经纪人自行加戏,随机应变

这一点也是JVM给Java程序员的自由,很多著名的产品就是在这个点上做了文章。

(4)加载到哪里去?

这个问题最好回答:内存,具体指的是JVM的运行时数据区,再具体一点是运行时数据区中的方法区[3]

[3]:本文聚焦类加载机制的全貌,以后再其他文章展开

(5)何时加载?

类加载发生在运行时,这也是Java、C#这类语言推崇的动态性。

动态性是一把双刃剑,运行时加载意味着需要"边执行,边连接"。
这就好像女团经纪人不是提前把"剧本"烂熟于胸,而是到了女团演出现场,才掏出"剧本",现场理解、现场执行。
以现实生活的经验,这样的经纪人,看起来不太靠谱。

当然,动态性一定是源于某些特定场景和需求,Java为了靠谱,也引出了虚拟机中另一个大的课题:JIT(即时编译),围绕着"如何提升运行时的编译效率"会有很多有趣的故事。

(6)加载流程有几步?

在(2)中我们提到女团的经纪人要无差错地仔细阅读"剧本"的电子件,关键词是无差错
我们再用一张表,类比一下[4]

加载流程? 经纪人阅读剧本的流程?
STEP1.加载(Load):将字节码文件变成内存的数据结构 STEP1.加载:经纪人打开剧本,读了一遍剧本
STEP2.连接(Link) STEP2.连接
STEP2.1.验证(Verify):验证文件格式、元数据、字节码、符号引用,最终保证JVM的安全可靠 STEP2.1.验证:经纪人若有所思的翻了翻剧本,确认没拿错剧本吧?不会是包装男团的剧本吧?
STEP2.2.准备(Prepare):"static"的内存分配与赋值 STEP2.2.准备:女团不管包装几个人(实例),她们肯定需要一个训练房(static变量),现在就租好
STEP2.3.解析(Resolve):符号引用转为直接引用。例如:类A有个成员变量,类型是类B,类B在哪呢? STEP2.3.解析:剧本中Lisa的那一页说她出道前在一个泰国舞团,泰国舞团的资料在剧本附件2,经纪人如果需要查看泰国舞团资料的时候,就知道去翻附件2
STEP3.初始化(Init):执行构造函数,触发关联类的解析 STEP3.初始化:经纪人前期准备差不过了,可以给Lisa(实例)打个电话:Lisa同学,快来做一下出道前的准备(构造函数)

表格中存在不严谨(通俗)的表达,但相信读者已经关注到了两个核心要点:

(1)加载流程有几步
(2)每一步的作用是什么

[4]:上述加载流程每一步存在一些JVM实现的细节,例如:上述步骤一定是顺序执行的吗?例如:直接引用需要反复解析吗?这些都有必要详细解读,本文暂不展开。

(7)加载流程如何实现?

至此,终于可以和本文开头的面试题呼应上了,前文我们探讨了

加载什么=>加载得到了什么=>从哪里加载=>加载到哪里去=>何时加载=>加载流程有几步

那么这都是JVM的规范、规格,怎么实现?类加载器就是类加载机制的具体实现。
不同类型的加载器相当于公司不同的角色,都去自己专属的文件夹去查找并加载类

Bootstrap加载器相当于经济公司老板
Extension加载器相当于经纪人
Application加载器相当于女团艺人

(8)类加载器的约束?

既然有不同的类加载器,它们之间必然有配合关系,否则两个人干了同一个工作,对外口径还不同,咋办?
JVM定义了这种配合关系,还取了个高大上的名字"双亲委派模型",笔者认为这种模型应该叫"保姆式管理模型"
还是一张表类比一下:

双亲委派模型 保姆式管理模型
STEP1.程序需要加载一个类 STEP1.记者问Lisa:某天晚上和你一起上车的神秘男子是谁?
STEP2.Application加载器一脸懵逼的问Extention加载器,领导,你能加载不? STEP2.Lisa一脸懵逼的问经纪人,欧巴,你帮我回答一下嘛?
STEP3.Extention加载器无助的看着Bootstrap加载器,领导,你能加载不? STEP3.经纪人无助的看看经纪公司老板,老大,还是你回答一下吧
STEP4.Bootstrap加载器无奈的摇摇头:试试看吧,我能加载就加载,不能的话,Extension,还是你自己试试 STEP4.老板摇摇头:试试看吧,我能回答就回答,不能答复,经纪人,你自己试试
STEP5.(假设Bootstrap不能加载)Extension无奈的摇摇头:我自己试试吧,不能加载的话,Application,你自己试试吧。 STEP6.(假设老板不能答复)经纪人苦笑了:我试试吧,不能回答,Lisa,你自己上吧。
STEP7.(假设Extension不能加载):Application自己来吧 STEP7.(假设经纪人不能回答)Lisa娇羞道的回答记者:恩~~伦家也不知道...反正不是蔡徐坤...

双亲委派模型,本质上是说"领导先上,领导不行我再上"。
这种管理风格,自然也有弊端。历史上有4次破坏双亲委派模型[5]的事件。
破坏双亲委派模型的本质,是"管理团队的风格多样化",例如:"扁平化团队"、"先干了再说团队"等等。
[5]:每种"管理风格"也各有利弊,这也是JVM发展历程中可以仔细学习的技术点,笔者在后续文章中再来探讨。

0x03 小结

我们从一道面试题开始,通过8个问题看到了类加载机制的全貌。

加载什么->加载得到了什么->从哪里加载->加载到哪里去->何时加载->加载流程有几步->加载流程如何实现->类加载器的约束

本文篇幅有限,还留下了一些重要、有趣的细节,未来笔者还会继续展开

字节码描述的信息
JVM能认识的数据结构
方法区的结构
加载流程每一步存在一些JVM实现的细节
破坏双亲委派模型

最后,笔者还想谈谈"理解优于记忆"的个人观点:深入理解JVM的原理对于实战的意义就是"先验知识",是"性能调优、内存泄露、OSGI"等疑难杂症、高级框架的"基础",如果能看到这类面试题背后的Why、What、How,您就获得了探寻计算机秘境的不二法门。

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