Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What about the Old GC problems caused by Groovy scripts?

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

这篇文章主要为大家展示了"Groovy脚本引发的 Old GC问题怎么办",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"Groovy脚本引发的 Old GC问题怎么办"这篇文章吧。

示例代码如下

ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByName("groovy");String function = String.format("def getTargetParamValue(%s) {return \"%s\"}", "o", "$o");engine.eval(function);Invocable invocable = (Invocable) engine;Object result = invocable.invokeFunction("getTargetParamValue", "test-string");System.out.println(result);

这段代码定义了一个Groovy的方法,根据传进去的参数返回对应的值。

由于生产环境流量很大,这段代码被频繁执行。测试时的代码如下

public class ScriptEngineTest { public static void main(String[] args) { ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("groovy"); //测试时改为死循环 for (int i = 0;; i++) { try { String function = String.format("def getTargetParamValue(%s) {return \"%s\"}", "o", "$o"); engine.eval(function); Invocable invocable = (Invocable) engine; Object result = invocable.invokeFunction("getTargetParamValue", "test-string"); System.out.println(result); TimeUnit.MICROSECONDS.sleep(100); System.out.println(new Date().toLocaleString()); } catch (Exception e) { String errorMsg = String.format("异常!%s", e.getMessage()); System.out.println(errorMsg); } } }}

模拟生产环境的情况,每秒钟执行10次。通过VusualVM观察JVM

CPU使用情况,可以看到在每次堆内存扩容的时候,CPU使用量会有明显增加

堆内存使用情况

metaspace使用量一直在增加

类加载情况,total loaded classes一直在增加

线程

dump内存

可见,每次循环中生成的 Groovy method在方法执行完成之后并没有被释放掉,导致metaspace的使用量一直增加,最终撑爆JVM

针对以上问题,解决方法为每次将生成的方法缓存下了,下次要执行的时候从缓存中取。

private final ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();private Object getInvokeResult(Object targetParam, String paramName, String expression) throws Exception { //targetParamClassName="com.umgsai.web.home.vo.NodeVO" String targetParamClassName = targetParam.getClass().getName(); //expression="$nodeVO.bizOwner" //paramName="nodeVO" String functionKey = String.format("%s_%s_%s", targetParamClassName, paramName, expression); functionKey = StringUtil.replaceChars(functionKey, "$", ""); functionKey = StringUtil.replaceChars(functionKey, ".", "_"); //functionKey为方法的名称和concurrentHashMap的key,这里需要去掉特殊字符 Invocable invocable = concurrentHashMap.get(functionKey); if (invocable != null) { //如果缓存中有,直接调用 return invocable.invokeFunction(functionKey, targetParam); } //如果缓存中没有,生成方法,并且存到concurrentHashMap synchronized (lock) { invocable = concurrentHashMap.get(functionKey); if (invocable == null) { String function = String.format("def %s(%s) {return \"%s\"}", functionKey, paramName, expression); engine.eval(function); invocable = (Invocable) engine; concurrentHashMap.put(functionKey, invocable); if (log.isInfoEnabled()) { String msg = String.format("Create new Groovy function, functionKey=%s, paramName=%s, expression=%s", functionKey, paramName, expression); log.info(msg); } } } if (log.isInfoEnabled()) { log.info(String.format("Groovy function concurrentHashMap.size=%d", concurrentHashMap.size())); } return invocable.invokeFunction(functionKey, targetParam);}以上是"Groovy脚本引发的 Old GC问题怎么办"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report