关于 "Unloading class sun.reflect.GeneratedSerial...

最近,由于项目需要,要在一个Tomcat上部署多个Web应用。考虑到Tomcat的最大堆大小为128MB,所以我对Tomcat的JVM参数做以下调整,并输出GC日志。参数如下

1 -Xms256m -Xmx512m -XX:PermSize=128M -XX:MaxPermSize=512M -Xloggc:D:/TomcatGc.log

然而在应用启动完成之后,在控制台不断输出以下“奇怪信息

1 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor339]
2 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor336]
3 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor341]
4 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor342]
5 [Unloading class sun.reflect.GeneratedSerializationConstructorAccessor340]

查看输出的GC日志,发现JVM从394.237S到2040.453s之间都在频繁地进行FullGC


关于 "Unloading class sun.reflect.GeneratedSerial..._第1张图片  


要知道JVM频繁地进行FullGC肯定不是什么好事情。于是就通过Google去搜索是什么原因导致那些“奇怪信息”的输出。


网上有许多回答都说是由于堆空间不够,JVM正尝试回收一些无用的对象。我在StackOverFlow上也发起相关的提问,给的回答也是这个 所以就信以为真,开始加大堆大小,调整参数如下:

1 -Xms512m -Xmx1024m -XX:PermSize=128M  -XX:MaxPermSize=512M -Xloggc:D:/TomcatGc.log

在应用启动完成之后,一开始并没有立即出现那些“奇怪信息”。但是在大约过了10分钟左右。控制台又不断输出上述“奇怪信息”。

经过一番折腾之后,我终于否决了堆空间不够导致那些”奇怪信息“输出的回答了,这哪里是这个原因导致的,简直就是坑爹。


那到底是什么原因导致的呢?回想起自己以前学过的JVM的知识。JVM运行时数据区域有分为方法区和堆。方法区(也叫永久代)用于存储类型信息、常量和静态变量等。堆空间用于存储对象和数组等。根据GC算法,堆空间又分为新生代和老年代。在新生代中会触发MinorGC(也称GC),老年代会触发MajorGC(也称Full GC).关于更多的信息可以参考我之前的文章


然而很多人都忽略了方法区也可以存在GC操作。这次悲剧的产生也是由于自己开始忽略这点导致的。要知道方法区的GC主要回收两部分内容:废弃常量和无用的类(注意这里的类和对象是两个不同的概念)。


判断一个类是否是无用的类需要满足下面3个条件:
1.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
2.加载该类的ClassLoader已经被回收
 
3.该类对应的Java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法


JVM可以对满足上述3个条件的无用类进行回收,这里说的仅仅是“可以”,而不是和对象一样,不使用了就必然会回收。是否对类进行回收,JVM提供了-Xnoclassgc参数进行控制。于是,我在Tomcat的Jvm参数里加上 -Xnoclassgc并限制 -XX:PermSize=128M   -XX:MaxPermSize=128M.重新启动Tomcat后,上述“奇怪信息”就不在出现了,并抛出了OutOfMemory  PermGen space 异常。关于 OutOfMemory  PermGen space 异常。这里也有一个非常有趣的讨论,大家可以看下。

总结:

    在大量使用发射、动态代理、cglib等框架比如Spring、hibernate等,都需要虚拟机具备类卸载的功能,以保证方法区不会溢出。如果限制类卸载功能及限制 PermSize大小,相信方法区很快就会溢出。所以那些“奇怪信息”也属于正常的输出。另外也可以通过调大 PermSize的值已保证有足够的空间来装载这些类信息,这样,“奇怪信息”就可能不会输出了。

1.区分JVM的中永久代、新生代和老年代的概念。记住Full GC和GC都发生在堆中。

2.导致频繁的Full GC的原因是堆空间大小不够,但是奇怪的信息输出绝不是堆空间不足产生。

3.折腾一天算是浪费时间,但是从中也学到和巩固不少知识也算是因祸得福。

你可能感兴趣的:(关于 "Unloading class sun.reflect.GeneratedSerial...)