我是靠谱客的博主 温暖斑马,最近开发中收集的这篇文章主要介绍groovy与java集成的坑背景坑测试class检测,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

背景

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

最后

以上就是温暖斑马为你收集整理的groovy与java集成的坑背景坑测试class检测的全部内容,希望文章能够帮你解决groovy与java集成的坑背景坑测试class检测所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(63)

评论列表共有 0 条评论

立即
投稿
返回
顶部