首页 > 其他分享 >【JVM】类的⽣命周期和类加载的过程

【JVM】类的⽣命周期和类加载的过程

时间:2024-06-18 12:27:51浏览次数:10  
标签:类库 初始化 周期 ClassLoader JVM 父类 加载

在Java中,类的生命周期和类加载过程是Java虚拟机(JVM)管理的核心部分。类的生命周期包括从类被加载到内存直到类被卸载的整个过程。类加载过程可以细分为多个阶段:加载、链接(包括验证、准备、解析)、初始化和使用。以下是详细的描述:

类的生命周期

  1. 加载(Loading)

    • 定义:将类的字节码从不同的源(如文件、网络等)加载到内存中,并生成一个代表这个类的Class对象。
    • 过程
      1. 通过类的全限定名获取定义此类的二进制字节流
      2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
      3. 在内存中生成一个代表这个类的Class对象,作为方法区数据结构的访问入口。
  2. 链接(Linking)

    • 定义:将类的二进制数据合并到JVM的运行时环境中。
    • 过程
      1. 验证(Verification):确保字节码的正确性和安全性。
        • 目的是保证加载的类符合JVM规范,不会危害虚拟机。
        • 验证的内容包括文件格式验证、元数据验证、字节码验证等。
      2. 准备(Preparation):为类的静态变量分配内存,并将其初始化为默认值。
        • 静态变量分配内存并初始化为零值,如int型的变量被初始化为0boolean型的变量被初始化为false
      3. 解析(Resolution):将常量池中的符号引用转换为直接引用。
        • 将类、字段、方法的符号引用替换为直接引用,这一过程通常在类初始化后进行,但也可以在运行时的某个阶段进行。
  3. 初始化(Initialization)

    • 定义:对类的静态变量赋初值,并执行静态代码块。
    • 过程
      • 执行类构造器<clinit>()方法。此方法是由编译器自动收集类中的所有静态变量的赋值动作和静态代码块中的语句合并产生的。
      • 若类有父类,则先初始化父类。
  4. 使用(Usage)

    • 定义:类加载到内存后,可以被实例化、调用其静态方法和字段。
    • 过程
      • 创建类的实例、调用类的静态字段和方法。
  5. 卸载(Unloading)

    • 定义:类在内存中占用的资源被释放。
    • 过程
      • 类卸载是由JVM的垃圾收集器完成的。当类的所有实例都被垃圾回收时,并且该类的ClassLoader实例也没有被引用,类将被卸载。

类加载器(Class Loader)

Java的类加载器负责动态地加载类。JVM提供了以下几种类型的类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)

    • 加载:核心类库,如rt.jar,在JRE的lib目录下。
    • 实现:由C++实现,嵌入在JVM内部。
  2. 扩展类加载器(Extension ClassLoader)

    • 加载:扩展类库,位于jre/lib/ext目录或由系统变量java.ext.dirs指定的路径下的类库。
    • 实现:由Java实现,类名为sun.misc.Launcher$ExtClassLoader
  3. 应用程序类加载器(Application ClassLoader)

    • 加载:应用程序的类路径(classpath)下的类库。
    • 实现:由Java实现,类名为sun.misc.Launcher$AppClassLoader
  4. 自定义类加载器(Custom ClassLoader)

    • 定义:用户可以自定义类加载器,通过继承java.lang.ClassLoader类来实现。
    • 用途:满足特定的类加载需求,例如从网络加载类、对类进行加密和解密等。

类加载过程

  1. 加载(Loading)

    • 由类加载器读取类文件的二进制数据,并将其转换为方法区中的运行时数据结构。
    • 创建一个代表这个类的Class对象。
  2. 链接(Linking)

    • 验证(Verification):确保字节码文件的正确性和安全性。
    • 准备(Preparation):为类的静态变量分配内存,并将其初始化为默认值。
    • 解析(Resolution):将常量池中的符号引用转换为直接引用。
  3. 初始化(Initialization)

    • 执行类构造器<clinit>()方法。
    • 按照类加载顺序,从父类到子类依次执行。
  4. 使用(Usage)

    • 创建类的实例、访问静态变量和静态方法。
  5. 卸载(Unloading)

    • 当类的所有实例被垃圾收集器回收,并且没有对该类的引用时,类卸载,释放内存。

类加载的双亲委派模型

双亲委派模型确保类加载器在加载类时,先委派给父类加载器尝试加载类。如果父类加载器无法加载,才由当前加载器尝试加载。这一机制确保核心类库不会被重复加载,也防止了核心类库被篡改。

过程:
  1. 检查当前类加载器是否已加载此类
  2. 委派给父类加载器加载
  3. 父类加载器递归上述过程
  4. 如果父类加载器未能加载此类,由当前加载器加载

示例代码

以下是一个简单的自定义类加载器示例:

import java.io.*;

public class CustomClassLoader extends ClassLoader {
    private String classPath;

    public CustomClassLoader(String classPath) {
        this.classPath = classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }

    private byte[] loadClassData(String className) {
        String fileName = classPath + File.separatorChar + className.replace('.', File.separatorChar) + ".class";
        try (InputStream inputStream = new FileInputStream(fileName);
             ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
            int nextValue = 0;
            while ((nextValue = inputStream.read()) != -1) {
                byteStream.write(nextValue);
            }
            return byteStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        CustomClassLoader classLoader = new CustomClassLoader("path/to/classes");
        Class<?> clazz = classLoader.loadClass("com.example.MyClass");
        Object instance = clazz.getDeclaredConstructor().newInstance();
        System.out.println(instance.getClass().getClassLoader());
    }
}

该自定义类加载器通过指定的路径加载类文件,展示了类加载的基本过程和原理。

总结

类的生命周期包括加载、链接、初始化、使用和卸载五个阶段。类加载过程则涉及到多个细节,包括验证、准备、解析和初始化。双亲委派模型确保了类加载的安全性和一致性。掌握这些知识可以更好地理解和优化Java应用程序的性能。

标签:类库,初始化,周期,ClassLoader,JVM,父类,加载
From: https://blog.csdn.net/hui_zai_/article/details/139710510

相关文章

  • docker镜像压缩包加载到镜像系统 docker load、将已拉取的镜像打包下载到本地docker
    当系统无法连接外网去拉取镜像的时候可以将下载好的镜像压缩包 *.tgz 、*.tar.gz 等上传至系统里、再经过docker指令加载到镜像镜像加载指令: dockerload-i 镜像压缩包名    # -i 指定要加载的镜像包#这个指令只是加载镜像文件不会启动镜像容器 ......
  • Pytorch数据加载与使用
    前言在训练的时候通常使用Dataset来处理数据集。Dataset的作用提供一个方式获取数据内容和标签(label)。实战fromtorch.utils.dataimportDatasetfromPILimportImageimportosclassget_data(Dataset):def__init__(self,root_dir,label_dir):self.r......
  • 2024-06-17-Spring 源码阅读(三)Bean 的生命周期
    由于Spring源码非常多,博客中贴源码会占用大量篇幅,阅读困难。详细分析部分会以commit提交形式关联源码提交,画图例来说明源码整体逻辑。Bean生命周期主体逻辑相关代码:Bean的基本创建流程、lazyInit、循环依赖Bean对象创建基本流程通过最开始的关键时机点分析,我们知道Bean......
  • Spring容器系列-bean的生命周期
    Spring容器系列-bean的生命周期  bean的生命周期从调用beanFactory的getBean开始,到这个bean被销毁,可以总结为以下七个阶段:  1. 处理名称,检查缓存  2.处理父子容器  3.处理dependsOn  4.选择scope策略  5.创建bean  6.类型转......
  • maven 加载不到 mybatis xml 配置文件
     <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin>......
  • 知识库的创建(1) - KnowledgeFile文件加载和分割
    文章目录前言一、类的初始化方法`__init__`1.参数解析2.初始化步骤二、方法`file2docs`1.功能2.参数3.步骤三、方法`docs2texts`1.功能2.参数3.步骤四、方法`file2text`1.功能2.参数3.步骤五、方法`file_exist`1.功能2.返回3.方法`get_mtim......
  • 【JVM】G1 垃圾收集器的垃圾收集过程
    G1(GarbageFirst)垃圾收集器是Java虚拟机(JVM)中的一种垃圾收集器,设计目标是提供高吞吐量和低停顿时间的垃圾收集。G1收集器将堆划分为多个大小相等的独立区域(Region),并通过并行和并发的方式进行垃圾回收。G1收集器可以回收年轻代(YoungGeneration)和老年代(OldGeneration)的垃圾......
  • 【JVM】CMS 收集器的垃圾收集过程
    CMS(ConcurrentMark-Sweep)收集器是Java虚拟机(JVM)中的一种垃圾收集器,它主要面向老年代(OldGeneration)的垃圾回收。CMS收集器的目标是最小化垃圾收集的停顿时间,从而提高应用程序的响应性。CMS垃圾收集过程主要分为以下几个阶段:初始标记(InitialMarking):这一阶段标记所有直接......
  • Bean生命周期
    目录一、bean生命周期基本流程二、流程细节1、初始化方法和销毁方法1)自定义式:2)接口式3)声明式4)执行顺序2、InstantiationAwareBeanPostProcessor实例化后置处理器2、BeanPostProcessor初始化后置处理器3、xxxAware接口三、总结执行流程一、bean生命周期基本流程......
  • 【2】软件生命周期
    【一】为什么要测试?【1】软件的非正常运行(有些软件在电量低的情况下不能运行)或其自身的缺陷Bug会引发很多问题。【2】软件是由开发人员编写代码和文档组成的,是人都有可能犯错,测试的工作是需要对开发出来的软件进行测试。【3】环境也会影响软件,以致出现软件失效的现象。【4】测......