JVM调优笔记(二)细聊类加载器

类加载器

作用
  • 在加载阶段(Load),读取字节码,将字节码加载进JVM,转换成java.lang.Class对象
  • 确定类在JVM中的唯一性。(子父级的关系限制了类的唯一性,全限定名一致的类,如果类加载器不同,也并不是同一个类)
分类/分层

java1.2版本中,只有Bootstrap的类加载器,这种情况下,很容易造成java自身的一些核心类由于同全限定名而被覆盖,不安全,因此对于类的安全性,信任考虑,进行了分层,java核心类>安装扩展类>自定义类

加载器分类层级(数字越小,层级越高)加载内容备注
Bootstrap ClassLoader1负责加载$JAVA_HOME中 jre/lib/rt.jar 里所有的class或Xbootclassoath选项指定的jar包。C++实现,不可访问
Extension ClassLoader2负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar 或 -Djava.ext.dirs指定目录下的jar包。
App ClassLoader3负责加载classpath中指定的jar包及 Djava.class.path 所指定目录下的类和jar包。
Custom ClassLoader4通过java.lang.ClassLoader的子类自定义加载classTomcat使用的这种方式
主要特性
全盘负责
  • 当一个类加载器负责加载当前类的时候,当前类所依赖引用的其他类,也将有该类加载器负责加载引入,除非显式的指定类加载器
  • 类加载器加载引入的含义是指:指定类的加载入口,实际上究竟由谁加载,则由父类委托机制完成
父类委托(双亲委派)
  • 子类如果没有加载过类,则交由父类加载
  • 父类无法加载,则交由子类查找加载

在这里插入图片描述

缓存机制
  • 缓存机制保证加载过的Class在内存中缓存
  • 优先从缓存中读取,找不到再Load
  • 缓存很难被卸载,因此需要很多时候更改了字节码文件,需要重启JVM
  • 相同的Class的loadClass();只会调用一次,类变量因此只初始化一次
loadClass源码
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
双亲委派问题
  • 三方服务的问题,例如数据库驱动包java.sql.Driver
打破双亲委派
SPI(service provider interface)

Java核心类中定义了很多接口和调用逻辑,但是没有具体的实现。SPI的方式,是自定义实现该接口的实现类,并且在META-INF/services下注册实现类,供核心类库使用,例如JDBC的DriverManager。

OSGI

通过卸载更新类加载器,同事卸载和替换类,实现代码的热部署。

自定义类加载器

自定义字节码的查找流程,重写loadClass

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值