Drools引发的PermGen OOM异常的跟踪

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

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

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

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


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



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

  • A: 其实不加参数,JDK6U23以上都会自动卸载不用的类(亲测),6U23以下没测试过。
  • 2.如果遇到,不管加或者不加参数,都没有主动卸载类的话,一般是什么原因?

  • A: 由于类被JNI Global引用了
  • 3.jni global标记的类是不是不会被GC?

  • A: 是的
  • 4.为什么这些类有JNI Global标记,我该从哪里入手?

  • A: 使用了-agentlib:hprof=cpu=samples参数导致的,两个JBoss参数不一样
  • 5.http://hllvm.group.iteye.com/group/topic/37664 这个帖子的楼主最后说是YoungGC影响FullGC的触发,这个靠谱么?

  • A: 应该不靠谱。。



记录一些知识和调试方法:

  • JAVA permGen的OOM一般来说只有两种原因:

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



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



补充添加,再不添加就忘了: Drools的配置有个shadowProxy属性,设置一下能避免每次生成新的类,不过这个属性是否能解决问题 有待研究,如果需要一些动态功能的话估计会出问题。
RuleBaseConfiguration conf = new RuleBaseConfiguration();
conf.setShadowProxy( false );
PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl(new StringReader(ruleScript));
RuleBase ruleBase = RuleBaseFactory.newRuleBase(conf);
  • 大小: 43 KB
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值