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,您就取得了探寻计算机秘境的不二法门。