结合JVM源码浅谈Java类加载器

一、前言

之前文章 Java 类加载器揭秘 从Java层面讲解了Java类加载器的原理,这里我们结合JVM源码在稍微深入讲解下。

二、Java类加载器的委托机制

Java 类加载器使用的是委托机制,也就是一个类加载器在加载一个类时候会首先尝试让父类加载器来加载。那么问题来了,为啥使用这种方式?

使用委托第一这样可以避免重复加载,第二,考虑到安全因素,下面我们看下ClassLoader类的loadClass方法:

结合JVM源码浅谈Java类加载器_第1张图片

代码(1)表示从 JVM 缓存查找该类,如果该类之前被加载过,则直接从 JVM 缓存返回该类。

代码(2)表示如果 JVM 缓存不存在该类,则看当前类加载器是否有父加载器,如果有的话则委托父类加载器进行加载,否者调用(3),委托 BootStrapClassloader 进行加载,如果还是没有找到,则调用当前 Classloader 的 findclass 方法进行查找。

代码(4)则是从本地classloader指定路径进行查找,其中findClass方法在路径找到Class文件会加载二进制字节码到内存,然后后会调用native方法defineClass1解析字节码为JVM内部的kclass对象,然后存放到Java堆的方法区。

代码(5)则是当字节码加载到内存后进行链接操作,对文件格式和字节码验证,并为 static 字段分配空间并初始化,符号引用转为直接引用,访问控制,方法覆盖等,本文对这些不进入深入探讨。

三、JVM源码之defineClass1如何解析字节码文件

本节使用的openjdk7的源码,JVM源码中defineClass1的订阅是在ClassLoader.c文件,其解析时序图如下:

结合JVM源码浅谈Java类加载器_第2张图片

image.png

可知步骤(8)具体解析字节码文件,步骤(17)添加加载的类到系统词典Map里面,

结合JVM源码浅谈Java类加载器_第3张图片

其中key使用类的包路径+类名,类加载器两者确定,value则为具体加载的类对应的instanceKlassHandle对象,其中维护这kclass对象。也就是系统词典里面使用类加载器和类的包路径类名唯一确定一个类。这也验证了在Java中同一个类使用两个类加载器进行加载后,加载的两个类是不一样的,是不能相互赋值的。

四、JVM源码之findLoadedClass0如何查找一个类是否被加载过了

findLoadedClass0也是在ClassLoader.c文件里面,其查找时序图:

结合JVM源码浅谈Java类加载器_第4张图片

image.png

如上时序图主要看 SystemDictionary的find方法:

结合JVM源码浅谈Java类加载器_第5张图片

可知在查找一个类是否已经被加载过后,也是从系统词典里面根据类名和类加载器去查找是否存在的。

五、总结

本文从JVM源码角度分析了Java中唯一含有包路径的类名和类加载器唯一确定了一个类,在全局系统词典里面就是根据包路径的类名和类加载器计算加载的类对应的key的。

最后 高性能 RPC 框架 Dubbo 从入门到深入 已经出炉,单击下方 阅读原文 既可以进入^^

你可能感兴趣的:(结合JVM源码浅谈Java类加载器)