热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Groovy脚本引发的OldGC问题

本文由编程笔记#小编为大家整理,主要介绍了Groovy 脚本引发的 Old GC问题相关的知识,希望对你有一定的参考价值。 近期上线了一个系统,鉴权部分使用了Groovy脚本,示例代码如下Script
本文由编程笔记#小编为大家整理,主要介绍了Groovy 脚本引发的 Old GC问题相关的知识,希望对你有一定的参考价值。


近期上线了一个系统,鉴权部分使用了Groovy脚本,示例代码如下

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);
}

参考 http://www.zgxue.com/120/1204001.html
https://www.cnblogs.com/fourspirit/p/4332154.html
https://www.jianshu.com/p/b1a46cc02377

转载请注明出处 https://www.cnblogs.com/umgsai/p/10742271.html


推荐阅读
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
author-avatar
添莺_764
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有