据说99.99%的人都会答错的类加载的问题

作者:媒体转发 时间:2019-03-07 01:03

字号

首先还是把问题抛给大家,这个问题也是我厂同学在做一个性能分析产品的时候碰到的一个问题。

同一个类加载器对象是否可以加载同一个类文件多次并且得到多个Class对象而都可以被java层使用吗?

请仔细注意上面的描述里几个关键的词

同一个类加载器:意味着不是每次都new一个类加载器对象,我知道有些对类加载器有点理解的同学肯定会想到这点。我们这里强调的是同一个类加载器对象去加载。

同一个类文件:意味着类文件里的信息都一致,不存在修改的情况,至少名字不能改。因为有些同学会钻空子,比如说拿到类文件然后修改名字啥的,哈哈。

多个Class对象:意味着每次创建都是新的Class对象,并不是返回同一个Class对象。

都可以被java层使用:意味着Java层能感知到,或许对我公众号关注挺久的同学看过我的一些文章,知道我这里说的是什么,不知道的可以翻翻我前面的文章,这里卖个关子,不直接告诉你哪篇文章,稍微提示一下和内存GC有关。

虽然有些标题党的意思,不过我觉得标题里的99.99%说得应该不夸张,这个比例或许应该更大,不过还是请认真作答,不要随便选,我知道肯定有人会随便选的,哈哈。

正常的类加载

这里提正常的类加载,也是我们大家理解的类加载机制,不过我稍微说得深一点,从JVM实现角度来说一下。在JVM里有一个数据结构叫做SystemDictonary,这个结构主要就是用来检索我们常说的类信息,这些类信息对应的结构是klass,对SystemDictonary的理解,可以认为就是一个Hashtable,key是类加载器对象+类的名字,value是指向klass的地址。这样当我们任意一个类加载器去正常加载类的时候,就会到这个SystemDictonary中去查找,看是否有这么一个klass可以返回,如果有就返回它,否则就会去创建一个新的并放到结构里,其中委托类加载过程我就不说了。

那这么一说看起来不可能出现同一个类加载器加载同一个类多次的情况。

正常情况下也确实是这样的。

奇怪的现象

然而我们从java进程的内存结构里却看到过类似这样的一些现象,以下是我们性能分析产品里的部分截图

据说99.99%的人都会答错的类加载的问题

在这个现象里,名字为java.lang.invoke.LambdaForm$BMH的类有多个,并且其类加载器都是BootstrapClassLoader,也就是同一个类加载器居然加载了同一个类多次。这是我们的分析工具有问题吗?显然不是,因为我们从内存里读到的就是这样的信息。

现象模拟

上面的这个现象看起来和lambda有一定关系,不过实际上并不仅仅lambda才有这种情况,我们可以来模拟一下

public static void main(String args[]) throws Throwable { 

       Field f = Unsafe.class.getDeclaredField("theUnsafe"); 

       f.setAccessible(true); 

       Unsafe unsafe = (Unsafe) f.get(null); 

       String filePath = "/Users/nijiaben/AA.class"

       byte[] buffer =getFileContent(filePath); 

       Class<?> c1 = unsafe.defineAnonymousClass(UnsafeTest.class, buffer, null); 

       Class<?> c2 = unsafe.defineAnonymousClass(UnsafeTest.class, buffer, null); 

       System.out.println(c1 == c2); 

   } 

上述代码其实就是通过Unsafe这个对象的defineAnonymousClass方法来加载同一个类文件两遍得到两个Class对象,最终我们输出为false。这也就是说c1和c2其实是两个不同的对象。

因为我们的类文件都是一样的,也就是字节码里的类名也是完全一样的,因此在jvm里的类对象的名字其实也都是一样的。不过这里我要提一点的是,如果将c1和c2的名字打印出来,会发现有些区别,分别会在类名后面加上一个/hashCode值,这个hash值是对应的Class对象的hashCode值。这个其实是JVM里的一个特殊处理。

另外你无法通过java层面的其他api,比如Class.forName来获取到这种class,所以你要保存好这个得到的Class对象才能后面继续使用它。

defineAnonymousClass的解说

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
关键词 >>类加载 java 内存
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接