面试题:JVM类加载机制 -- 双亲委派机制

前置知识

JVM类加载机制主要有如下三种方式

  1. 全盘负责:指当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责加载,除非显示使用另一个类加载器来载入
  2. 双亲委派:指先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该Class
  3. 缓存机制:当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为什么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因

JVM自带的类加载器

  1. 启动类加载器(Boostrap ClassLoader)负责载Java核心类库。出于安全考虑,引导类加载器只加载器包名为 java, javax , sun等开头的类
    • 使用C/C++语言实现,嵌套在JVM内部。不继承于 java.lang.ClassLoader,没有父类加载器
    • 负责加载扩展类加载器和应用类加载器,并为它们指定父类加载器
  2. 扩展类加载器(Extension ClassLoader)负责加载JRE的扩展目录。从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK系统安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的jar放在此目录下,也会自动由扩展类加载器加载
    • Java语言编写,由 sun.misc.Launcher$ExtClassLoader 实现,父类加载器为 null
    • 派生于 java.lang.ClassLoader类 
  3. 应用类加载器(Application ClassLoader)负责加载开发者自定义的类。该类加载器是程序中默认的类加载器
    • Java语言编写的,由 sun.misc.Launcher$AppClassLoader 实现,父类加载器为 ExtClassLoader。派生于 java.lang.ClassLoader类 

    • 可以通过 类名.class.getClassLoader() 或者 ClassLoader.getSystemClassLoader()来获得


JVM类加载机制 -- 双亲委派机制

双亲委派机制:如果一个类加载器收到类加载请求时,它并不会自己先去加载,而是把该请求委托给父类加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托加载任务,依次递归的方式,请求最终将到达顶层的启动类加载器。如果父类加载器可以完成类加载任务,就成功返回,若父加载器无法完成此加载任务,子加载器才会尝试自己从类全限定路径加载,如果都加载失败了,就会抛出ClassNotFoundException异常。加载过程图如下

双亲委派优点

  1. 可以避免开发者自定义的类动态的替换Java的核心类
    • 如java.lang.String。java核心API中定义类型不能被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改
  2. 可以避免全限定命名的类重复加载(使用findLoadClass()方法判断当前类是否已加载)
    • Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父类加载器已经加载了该类时,就没有必要子加载器再加载一次

注意:Java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类完全加载到JVM中,至于其他类,则按需加载。起到节省内存开销作用

 

 

posted @ 2022-07-02 22:23  伊文小哥  阅读(359)  评论(0编辑  收藏  举报