加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

groovy与java集成的坑

发布时间:2020-12-14 16:41:28 所属栏目:大数据 来源:网络整理
导读:背景 groovy用来和java集成,作为动态规则引擎使用,是非常不错的一个选择。简单来说,就是用java来执行一段groovy代码。可以通过一个简单的数据库配置,来动态的执行某段脚本。这样就可以实时得更改脚本,java就可以动态调用这段代码,从而达到灵活的在线变

背景

groovy用来和java集成,作为动态规则引擎使用,是非常不错的一个选择。简单来说,就是用java来执行一段groovy代码。可以通过一个简单的数据库配置,来动态的执行某段脚本。这样就可以实时得更改脚本,java就可以动态调用这段代码,从而达到灵活的在线变换的规则引擎。

假如不做任何优化的话,那么每次java执行一次groovy脚本,都会动态生成一个class,将导致class越来越多,最终导致JVM进行perm区爆满的问题。

测试

用以下脚本循环执行groovy代码

while(true){
            Binding binding = new Binding();
            binding.setVariable("x",10);
            binding.setVariable("language","Groovy");
            GroovyShell shell = new GroovyShell(binding);
            Object value = shell.evaluate("return x*2");//反复执行这段groovy脚本
            System.out.println(value);
        }

class检测

这里写图片描述


通过jconsole可以看到,class的数量线性增加,到了一定数量后就触发GC导致应用异常。

1、为什么Groovy每执行一次脚本,都会生成一个脚本对应的class对象?

因为一个ClassLoader对于同一个名字的类只能加载一次,都由GroovyClassLoader加载,那么当一个脚本里定义了C这个类之后,另外一个脚本再定义一个C类的话,GroovyClassLoader就无法加载了。

2、为什么InnerLoader加载的对应无法通过gc清理掉?

大家都知道,JVM中的Class只有满足以下三个条件,才能被GC回收,也就是该Class被卸载:1. 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例;2. 加载该类的ClassLoader已经被GC;3. 该类的java.lang.Class对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法。

在GroovyClassLoader代码中有一个class对象的缓存,进一步跟下去,发现每次编译脚本时都会在Map中缓存这个对象,即:setClassCacheEntry(clazz)。每次groovy编译脚本后,都会缓存该脚本的Class对象,下次编译该脚本时,会优先从缓存中读取,这样节省掉编译的时间。这个缓存的Map由GroovyClassLoader持有,key是脚本的类名,这就导致每个脚本对应的class对象都存在引用,无法被gc清理掉。

解释

每次groovy编译脚本的时候,都会生成一个名称为”script” + System.currentTimeMillis() + Math.abs(text.hashCode()) + “.groovy”的class对象。而此对象又会被map缓存起来,key就是刚才的名称,这样导致gc无法回收,从而导致fullgc

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读