Drools引发的PermGen OOM异常的跟踪

环境:
win7(64位)+JDK1.6 u45(32位)+JBoss5.10GA

缘由:
公司最近在做压力测试,发现permgen不停的涨,并且Full GC后类没有被卸载掉,换了个JBoss5.10GA,使用同样的启动参数(这里疏忽了,实际上参数不一样),发现类就可以卸载了。

原因:
发现我们使用的Drools这个第三方的包会不断地创建GeneratedSerializationConstructorAccessor + N这种类,看了下R大的帖子[url]http://rednaxelafx.iteye.com/blog/548536[/url] 大概知道了一些原理,这种情况是由于反射引起的。 类似会产生这种问题的第三方包还有Groovy(见R大帖子)和Xstream([url]http://www.myexception.cn/program/1310335.html[/url])

问题:
Drools生成类的问题这个我会去慢慢排查,看看是不是API调用的问题(堆栈见附件,主要是Drools的statefulSession.insert方法)。我主要还是想问一下PermGen在GC时候竟然不能回收类的问题。而且这种现象在换了JDK之后也会出现。


我试了下单独跑一个permgen OOM的测试用例,发现类是可以被卸载掉的,但是对上面有一个JBoss不能回收的问题实在是不解,我找了一下生成GeneratedSerializationConstructorAccessor 类的引用,发现只有 DelegatingClassLoader;并且我也跑过了jmap -permstat,发现这些都是dead的。 不回收情况的JvisualVM截图和家中不同的地方体现在, $classLoader$的后面有的标记(见附件),不知道这个和能不能回收有关系.

[img]http://dl2.iteye.com/upload/attachment/0101/5498/e4be295a-3487-335c-b035-cb0eabe6b4bf.jpg[/img]

问题和我自己的回答:
[list]
[*]1.JDK6如果不添加任何参数(如-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled),默认FullGC应该是会卸载类吧?除了这个参数,有没有其他的参数会影响类的卸载?

A: 其实不加参数,JDK6U23以上都会自动卸载不用的类(亲测),6U23以下没测试过。

[*]2.如果遇到,不管加或者不加参数,都没有主动卸载类的话,一般是什么原因?

A: 由于类被JNI Global引用了

[*]3.jni global标记的类是不是不会被GC?

A: 是的

[*][color=red]4.为什么这些类有JNI Global标记,我该从哪里入手?

A: 使用了-agentlib:hprof=cpu=samples参数导致的,两个JBoss参数不一样[/color]

[*]5.http://hllvm.group.iteye.com/group/topic/37664 这个帖子的楼主最后说是YoungGC影响FullGC的触发,这个靠谱么?

A: 应该不靠谱。。
[/list]


[b]记录一些知识和调试方法:[/b]

[list]
[*]JAVA permGen的OOM一般来说只有两种原因:

1. 生成了大量的Intern String,这时候就看你代码里面是不是有循环的添加string.intern()
2. Load了大量的类:如果是正常引入类导致的,一般加大permgen的size就可以;如果是由反射引起的,则要考虑这些动态生成并且动态引入的类是不是合理,如果对第三方库了解好的话看看能不能复用类,如果不好的话,起码保证这些类不被引用的时候被GC掉。
[*]通过加参数-verbose:class 或者 -XX:+TraceClassLoading -XX:+TraceClassUnloading可以看到2这种OOM的情况时,JVM到底加载了哪些类,进而可以跟踪哪里生成了这些类。
[*]JDK6U23以上都会自动卸载不用的类,关于什么是"不用的类",见R大的解答:[url]http://hllvm.group.iteye.com/group/topic/37664#259135[/url]
[*]一个有用的JVM参数链接[url]http://www.oschina.net/translate/hotspot-jvm-options-java-examples?cmp[/url]
[/list]


TODO:看下hprof, 看下Drools能不能不生成这么多类,C基础太差了,只能学习这些知识点,具体底层的原因就不懂了,残念。。


补充添加,再不添加就忘了: Drools的配置有个shadowProxy属性,设置一下能避免每次生成新的类,不过这个属性是否能解决问题[b]有待研究[/b],如果需要一些动态功能的话估计会出问题。
RuleBaseConfiguration conf = new RuleBaseConfiguration();
conf.setShadowProxy( false );
PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl(new StringReader(ruleScript));
RuleBase ruleBase = RuleBaseFactory.newRuleBase(conf);

你可能感兴趣的:(JVM)