第1课java_虚拟机基础
热度🔥:30 免费课程
授课语音
Java虚拟机介绍
1. 介绍
虚拟机是Java程序的执行引擎,使得同一份Java程序能够在不同的操作系统上运行。JVM负责将Java程序的字节码文件转换为特定的机器码并执行。这一过程的主要组成部分包括:
类加载器
类加载器负责将Java字节码加载到JVM中,并将这些字节码转换为方法区中的运行时数据结构。它的结构包含:
- 引导类加载器,这是所有其他类加载器的父类,负责加载JVM的核心类库,比如
java.lang.*
。 - 扩展类加载器,负责加载扩展库,通常位于
jre/lib/ext
目录下。 - 应用程序加载器,用于加载应用程序classpath路径中的类。
- 自定义类加载器,用户可以实现特定的类加载需求。
双亲委派机制是类加载器的一大特性。当一个类加载器接到加载请求时,它首先会委派给它的父类加载器去完成,只有在父类加载器无法加载时,子类加载器才会尝试加载。这一机制确保了类加载的安全性和一致性。
执行引擎
执行引擎负责执行从类加载器加载的字节码,主要由两个组件组成:
- 解释器,逐行将字节码解释为机器码。尽管这种执行方式速度较慢,但其启动时间较短。
- 即时编译器(JIT Compiler),在程序运行时将热点字节码(频繁执行的字节码)编译为本地机器码,从而提高执行效率,尽管这样会增加启动时间和内存占用。
垃圾回收器
垃圾回收器自动回收不再使用的对象,释放内存。垃圾回收机制包括标记-清除、标记-整理和复制算法等。现代JVM(如HotSpot)提供了多种垃圾回收器,如Serial、Parallel、CMS、G1等。
本地接口
通过JNI(Java Native Interface),允许Java代码调用本地操作系统的方法。
运行时数据区
运行时数据区是Java进程使用的内存区域,分为共享数据区和线程独享数据区:
共享数据区包括:
- 堆区:存储所有的对象和数组,垃圾回收器负责管理。
- 方法区:存储类的元数据、常量、静态变量和JIT编译后的代码。
- 运行时常量池:存储编译生成的字面量和符号引用。
线程独享区包括:
- 虚拟机栈区:存储局部变量、操作数、动态链接和方法出口等。
- 本地方法栈:为本地方法服务。
- 程序计数器:存储当前所执行字节码的行号指示器。
图示
类加载流程
类加载的流程分为四个步骤:
- 加载:将类的字节码读取到内存中,并创建一个
class
对象。 - 链接:分为三个阶段:
- 验证:确保字节码符合JVM规范,确保类的正确性。
- 准备:为类变量分配内存,并设置默认值。
- 解析:将类符号引用替换为内存地址或直接引用。
- 初始化:静态变量和代码块的初始化顺序为先初始化依赖的类,再初始化当前类。
图示
2. 核心代码
以下是ClassLoader类的核心实现,位于java.lang
包中。
public class ClassLoader {
// 加载类的主方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
// 先检查类是否已经被加载
Class<?> c = findLoadedClass(name);
if (c == null) {
// 如果类没有被加载,则调用findClass方法加载类
try {
c = findClass(name);
} catch (ClassNotFoundException e) {
// 继续委托给父类加载器,双亲委派机制
if (parent != null) {
c = parent.loadClass(name);
}
if (c == null) {
throw e; // 如果父类加载器也无法加载,抛出异常
}
}
}
return c; // 返回加载的类
}
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name); // 子类需实现
}
protected Class<?> findLoadedClass(String name) {
// 实际实现由子类提供
return null;
}
}
自定义类加载器的实现,通过继承ClassLoader来完成。
public class MyClassLoader extends ClassLoader {
private String classPath; // 类文件路径
public MyClassLoader(String classPath) {
this.classPath = classPath; // 初始化类文件路径
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 将类名转换为文件路径
String path = classPath + "/" + name.replace('.', '/') + ".class";
byte[] classData = loadClassData(path); // 加载类数据
if (classData != null) {
return defineClass(name, classData, 0, classData.length); // 定义类
}
throw new ClassNotFoundException(name); // 类未找到异常
}
private byte[] loadClassData(String path) {
// 实际实现需要读取文件内容到字节数组
return null; // 这里需要实现文件读取逻辑
}
}
以上就是关于Java虚拟机的介绍和核心代码示例。希望大家能够理解Java虚拟机的结构和类加载的基本原理。