深入Java Classloader(一) - JVM模型和类加载机制
Classloader是JVM模型的一部分,JVM通过Classloader动态加载class文件到内存中使用的。
所以要给出Classloader的定义十分简单,它就是Java中的一系列类,这些类的职责就是动态加载其他类。
但是,了解这样的定义意义不大,我们希望明白的是这一套机制是解决什么问题的。要了解这个问题,先从C说起。
从C说起(C语言的编译和连接过程)
假设我有三个.c文件,整个编译过程是这样的:
整个过程会有这样4个步骤:
- 预处理(Preprocessing):静态替换,处理预编译指令。
- 编译(Compilation):预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。
- 汇编(Assembly):汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。
- 链接(Linking):通过调用链接器ld来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件。
最终得到的是一个.exe(windows)或.out(linux)文件。
在运行的时候,是将整个输出文件(a.exe)读到内存里运行的:
可见,经过编译和汇编步骤,会生成直接给CPU执行的机器指令。机器码顾名思义就是0101的二进制代码。所以,执行C语言的时候,实际上是运行最底层的语言,这样的代码高效,却和芯片,操作系统紧密耦合在一起了。
Write Once, RunError Anywhere
Java在刚刚诞生的时候提出一个非常著名的宣传口号“Write Once, Run Anywhere”。它希望程序员写的代码能在不同的平台/硬件上执行,“与平台无关”。
平台无关性的两个基石是:
- 字节码存储格式。Java编译器会将.java文件编译为.class文件,.class文件就是能被JVM执行的代码,它包含Java虚拟机的指令集,符号表和其他辅助信息。
- Java虚拟机(JVM)。顾名思义它是加在应用层的一层抽象。从上层看,它就是CPU:加载并运行字节码代码,屏蔽了操作系统和硬件细节,对下,它将字节码翻译为CPU能执行的机器指令。
了解bytecode和JVM后,再来看看JAVA的编译,执行过程。
首先,是将.java文件编译成.class文件:
当JVM运行时,再按需加载这些.class到内存中:
可以看到,Java和C在编译过程中的一个差异是:在Java语言里面,类型的加载,连接,和初始化是在运行期间完成的。
结合整个JVM的结构模型,能更清楚的看到classloader的位置和机制:
有了这些背景知识,现在我们能清楚地给出相关定义:
- JVM在运行期间把.class文件加载到内存,并对数据进行校验,转换,和初始化的过程就是类加载机制。
- classloader就是实现这套机制的一系列类。
下一篇,说说类加载的工作机制。
参考资源
- JVM (Java Virtual Machine) Introduction (https://www.youtube.com/watch?v=G1ubVOl9IBw)