Java的Groovy执行器内存泄露(MetaSpace)问题分析与解决办法
环境与背景
在java程序中通过GroovyScriptEvaluator执行器创建脚本Script对象调用Groovy脚本语言来完成某些功能, ,会通过AppClassLoader或者GroovyClassLoader去生产一个随机的名称的Groovy的Script类对象,导致元数据,产生的class类会被AppClassLoader或者GroovyClassLoader内部对应的Map所引用,导致不不能满足被垃圾回收的条件, 在执行脚本期间,得到了 Out of Metaspace出错
jdk8, groovy 2.4.6版本
<dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy-all</artifactId><version>2.4.6</version></dependency>
执行脚本方式
1 Spring GroovyScriptEvaluator执行器
2.ScriptEngineManager 基于JDK的SPI方式提供的执行脚本引擎
3.基于GroovyShell
问题复现方式
GroovyScriptEngineImpl se;while (true)
{se = new GroovyScriptEngineImpl(new GroovyClassLoader());CompiledScript script = se.compile("println(\"hello\")");script.eval(se.createBindings());
}
或者
private static GroovyScriptEvaluator evaluator = new GroovyScriptEvaluator();public static Object evaluateScript(String script, Map<String, Object> context) {ScriptSource scriptSource = new StaticScriptSource(script);return evaluator.evaluate(scriptSource, context);}public static void main(String[] args) {while (true) {evaluateScript("1+2", Maps.newHashMap());}}
JVM调优复现参数
-Xms200m -Xmx200m -Xss1m -XX:MetaspaceSize=40m -XX:MaxMetaspaceSize=40m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime -Xloggc:C:\Users\admin\Desktop\GC\gc-%t.log -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\admin\Desktop\GC\memory.log
类加载机制-双亲委派
Groovy的ClassLoader体系:
Bootstrap ClassLoader
↑
sun.misc.Launcher.ExtClassLoader // 即Extension ClassLoader
↑
sun.misc.Launcher.AppClassLoader // 即System ClassLoader
↑
org.codehaus.groovy.tools.RootLoader // 以下为User Custom ClassLoader
↑
groovy.lang.GroovyClassLoader
↑
groovy.lang.GroovyClassLoader.InnerLoader
异常现象
groovy 2.4.6 版本
解决思路: 1. 更换版本groovy2.4.8
以及以上版本,则会回收Script类,可以解决问题,但是会存在性能问题
解决思路2: 升级jdk版本, 升级jdk版本11, 尝试解决类不会回收的问题
groovy 2.4.6 版本
出现问题
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
排查Metaspace方式
1. 通过jps命令,查看java进程pid
2. 通过jinfo 命令查看额外的java参数配置信息
3. 通过jmap用来查看内存信息,实例个数以及占用内存大小
- num:序号
- instances:实例数量
- bytes:占用空间大小
- class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
4. 通过jstat 命令查看堆内存各部分的使用量,以及加载类的数量
评估程序内存使用及GC压力整体情况
S0C:第一个幸存区的大小,单位KB
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小(元空间)
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间,单位s
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间,单位s
GCT:垃圾回收消耗总时间,单位s
堆内存统计
NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0C:第一个幸存区大小
S1C:第二个幸存区的大小
EC:伊甸园区的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:当前老年代大小
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代gc次数
FGC:老年代GC次数
jconsole 查看堆栈元数据等信息
分析内存溢出信息 jvisualvm
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (路径)
通过参数, 导入dump文件
- 查看相应的堆栈信息, 以及方法入栈/出栈等信息,
系统属性
显示线程
等确定代码异常位置 - 查看类信息, 找出类创建数量多的类, 是否有自己写的相关类信息,进行代码定位
代码解决方案
- 升级groovy版本为2.4.8或以上版本
@Slf4j
public class GroovyScriptUtil {public GroovyScriptUtil() {}private static final String EngineName = "groovy";private static ScriptEngine engine = null;static{ScriptEngineManager factory = new ScriptEngineManager();engine = factory.getEngineByName(EngineName);}public static Object evaluateScript(String script, Map<String, Object> params) {try {Bindings bindings = engine.createBindings();bindings.putAll(params);return engine.eval(script,bindings);} catch (Exception e) {log.error("script脚本执行异常,script:{},params:{}",script,params);log.error("script脚本执行异常:",e);return null;}}
}
public class GroovyUtils {private static GroovyShell groovyShell = new GroovyShell();private static Map<String, Script> scriptCache = new ConcurrentHashMap<>();private static <T> T invoke(String scriptText, String function, Object... objects) throws Exception {Script script;String cacheKey = DigestUtils.md5Hex(scriptText);if (scriptCache.containsKey(cacheKey)) {script = scriptCache.get(cacheKey);} else {script = groovyShell.parse(scriptText);scriptCache.put(cacheKey, script);}return (T) InvokerHelper.invokeMethod(script, function, objects);}
}
常用的JVM参数
-XX:+HeapDumpOnOutOfMemoryError:表示当JVM发生OOM时,自动生成DUMP文件。-XX:HeapDumpPath:表示生成DUMP文件的路径,也可以指定文件名称。-Xms 启动应用时,JVM 堆空间的初始大小值。
-Xmx 应用运行中,JVM 堆空间的极限值。为了不消耗扩大JVM堆空间分配的开销,将此参数和-Xms这个两个值设为相等,考虑到需要开线程,将此值设置为总内存的80%.
-Xss 单个线程堆栈大小值;JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K
-Xms 的默认值是物理内存的 1/64 但小于1G,-Xmx 的默认值是物理内存的 1/4 但小于1G
-Xmn 此参数硬性规定堆空间的新生代空间大小,推荐设为堆空间大小的1/4。
-XX:+UseParNewGC 开启此参数,多个CPU可并发进行垃圾回收,可提高垃圾回收的速度。此参数和+UseParallelGC,-XX:ParallelGCThreads搭配使用。
+UseParallelGC 年轻代使用并发收集,而年老代仍旧使用串行收集 。可提高系统的吞吐量。
XX:ParallelGCThreads 年轻代并行垃圾收集的前提下(对并发也有效果)的线程数,增加并行度.此值最好配置与处理器数目相等
-Xloggc:<file> 将 GC 状态记录在文件中 (带时间戳)
JVM 参数关系到系统的性能,而其中 -XX:PermSize,-XX:MaxPermSize,-Xms,-Xmx 和 -Xmn 这 5 个参数更是直接关系到系统的性能,系统是否会出现内存溢出。
-XX:PermSize 和 -XX:MaxPermSize 分别设置应用服务器启动时,永久存储区的初始大小和极限大小;在生产环境中强烈推荐将这个两个值设置为相同的值,以避免分配永久存储区的开销,如果不进行设置-XX:MaxPermSize ,则默认值为 64M (jdk1.8之前使用)
-XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX:MetaspaceSize: 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M,达到该值就会触发
full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超
过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。这个跟早期jdk版本的-XX:PermSize参数意思不一样,-
XX:PermSize代表永久代的初始容量。-Xloggc:/path/logs/gc-%t.log GC日志存储的文件路径,%t 表示每次启动时用时间戳命名日志文件,如 gc-2021-03-29_20-41-47.log。
-XX:+UseGCLogFileRotation 开启日志文件分割
-XX:NumberOfGCLogFiles=16 最多分割几个文件,超过之后从头开始写
-XX:GCLogFileSize=100M 每个文件存储的上限大小,超过就触发分割
-XX:+PrintGCDetails 打印GC详细信息
-XX:+PrintGCDateStamps 打印GC日期戳
-XX:+PrintTenuringDistribution 打印对象年龄分布日志,分析 GC 时的晋升情况和晋升导致的高暂停
-XX:+PrintHeapAtGC GC 后打印堆数据,用于对比一下 GC 前后的堆内存情况,更直观
-XX:+PrintReferenceGC 打印 Reference 处理信息
-XX:+PrintGCApplicationStoppedTime 打印 STW 暂停时间
java -XX:+PrintCommandLineFlags -version 查看JVM使用什么垃圾收集器-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=./ (路径)
jps 查看java进程号
jinfo
jstat
jstack
jamp
jconsole.exe
jvisualvm.exe
调优工具Arthas
支持 JDK6+, 采用命令行交互模式,可以方便的定位和诊断
线上程序运行问题。Arthas 官方文档十分详细,详见:https://alibaba.github.io/arthas
1.用java -jar运行即可,可以识别机器上所有Java进程
2. 选择识别的java进程号, 输入即可进入arthas 的控制台
3. 输入dashboard,可以查看整个进程的运行情况,线程、内存、GC、运行环境信息
4. 输入thread可以查看线程详细情况
5. 输入 jad加类的全名 可以反编译,这样可以方便我们查看线上代码是否是正确的版本
6. 使用 ognl 命令可以查看线上系统变量的值,甚至可以修改变量的值
7. 还有很多命令可以在官网查看,进行使用即可
参考
https://www.cnblogs.com/hanease/p/16131868.html
https://blog.csdn.net/ld851/article/details/111180179
https://blog.csdn.net/weixin_46017166/article/details/127820176
jvm: https://api.dandelioncloud.cn/article/details/1497067909796171778
相关文章:

Java的Groovy执行器内存泄露(MetaSpace)问题分析与解决办法
环境与背景 在java程序中通过GroovyScriptEvaluator执行器创建脚本Script对象调用Groovy脚本语言来完成某些功能, ,会通过AppClassLoader或者GroovyClassLoader去生产一个随机的名称的Groovy的Script类对象,导致元数据,产生的class类会被AppClassLoader或者GroovyClassLoader内…...

【linux】进程信号——信号的产生
进程信号一、信号概念1.1 信号理解二、产生信号2.1 通过键盘产生信号2.2 捕捉信号自定义signal2.3 系统调用接口产生信号2.3.1 向任意进程发送任意信号kill2.3.2 给自己发送任意信号raise2.3.3 给自己发送指定信号abort2.3.4 理解2.4 硬件异常产生信号2.4.1 除0异常2.4.2 野指针…...
部署OpenStack
部署 1. 环境配置 配置主机名 使用CRT软件连接controller节点和compute节点,用户名默认为root,密码默认为000000。连接上之后,使用linux命令修改节点主机名。 [rootcontroller ~]# hostnamectl set-hostname controller [rootcontroller …...

Java 运算符与类型转化
Java 运算符与类型转化 1 算术运算符 Java中的算术运算符主要有(加)、-(减)、*(乘)、/(除)、%(求余),它们都是二元运算符。 2 自增和自减运算…...
《C++ Primer Plus》第18章:探讨 C++ 新标准(2)
移动语义和右值引用 现在介绍本书前面未讨论的主题。C11 支持移动语义,这就提出了一些问题:为何需要移动语义?什么是移动语义?C11 如何支持它?下面首先讨论第一个问题。 为何需要移动语义 先来看 C11 之前的复制过程…...

QML定时器
QML使用Timer使用定时器 Timer 计时器可用于触发操作一次,或以给定的间隔重复触发。 常用属性: interval 设置触发器之间的间隔(以毫秒为单位)。 默认间隔为 1000 毫秒。 repeat 设置重复,为真,则以指定的…...

第三章 opengl之纹理
OpenGL纹理纹理环绕方式纹理过滤多级渐远纹理加载和创建纹理stb_image.h生成纹理纹理的应用纹理单元纹理 用stb_image.h库,原先用SOIL库也可以实现。 可以为每个顶点添加颜色来增加图形的细节。但是想得到一个真实的图形,需要足够多的顶点,…...
【Flink】FlinkSQL中执行计划以及如何用代码看执行计划
FilnkSQL怎么查询优化 Apache Flink 使用并扩展了 Apache Calcite 来执行复杂的查询优化。 这包括一系列基于规则和成本的优化,例如: • 基于 Apache Calcite 的子查询解相关 • 投影剪裁 • 分区剪裁 • 过滤器下推 • 子计划消除重复数据以避免重复计算 • 特殊子查询重写,…...

从业者必读,一篇文章轻松掌握DevOps核心概念和最佳技能实践!
文章目录前言一. DevOps的定义及由来二. DevOps的价值三. devops工具有哪些3.1 devops工程师的硬实力3.2 devops工程师的软实力总结前言 大家好,又见面了,我是沐风晓月,本文是对DevOps的总结,一篇文章告诉你什么是DevOps. 对很多…...

2023爱分析·一体化HR SaaS市场厂商评估报告:北森
目录 1.研究范围定义 2. 一体化HR SaaS市场分析 3.厂商评估:北森 4.入选证书 1.研究范围定义 研究范围 伴随数字化转型走向深入,企业人力资源数字化也进入快速发展阶段,人力资源的价值也得到了重新审视和定义。政策层面,《…...
JAVA练习67-二叉树的中序遍历
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-二叉树的中序遍历 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 3月3日练习…...

【JeecgBoot-Vue3】第1节 源码下载和环境安装与启动
目录 一. 资料 1. 源码下载 2. 官网启动文档 二、 前端开发环境安装 2.1 开发工具 2.2 前后端代码下载 2.3 前端启动 Step 1:安装nodejs npm Step 2:配置国内镜像(这里选阿里) Step 3:安装yarn Step 4&…...

WebAPI
WebAPI知识详解day11.Web API 基本认知作用和分类什么是DOM?DOM树的概念DOM对象2.获取DOM对象通过css选择器获取dom对象通过其他方法获取dom3.设置/修改DOM元素内容方法1. document.write() 方法方法2. 对象.innerText 属性方法3. 对象.innerHTML4.设置/修改DOM元素…...
Shell命令——date的用法
date命令可以用来显示或设定系统的日期与时间。 一、显示系统的日期与时间 (1)如果date命令后面不加任何参数,则会按照固定的格式显示时间信息: 星期几 月份 日 时:分:秒 时区 年xjhubuntu:~/iot/tmp$ date Fri Mar 3 16:56:4…...

XSS跨站脚本
XSS跨站脚本XSS简介XSS验证XSS危害XSS简介 XSS被称为跨站脚本攻击(Cross-site scripting),由于和CSS(Cascading Style Sheets)重名,所以改为XSS。XSS主要基于javascript语言完成恶意的攻击行为,因为javascript可以非常灵活的操作html、css和…...

【强烈建议收藏:MySQL面试必问系列之慢SQL优化专题】
一.知识回顾 学习本篇文章之前呢,我们可以先看一下【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】,看完这篇文章再来学习本篇文章可谓是如虎添翼。好的,那我们也不讲太多的废话,直接开始。 二.如何做慢SQL查询优化呢&…...
windows,liunx,java实现apk解压,去签名、重新签名,重新打包apk
背景:由于项目需要,需要将apk包加入服务端返回的静态资源文件到apk中,形成离线apk包供下载安装。经过调查研究,决定使用apktool实现。关于apktool的资料可以参考 https://blog.csdn.net/quantum7/article/details/124060620 htt…...

【Linux】进程信号
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉信号入门&…...

SpringBoot 集成Junit单元测试
学习文章: https://www.cnblogs.com/ysocean/p/6889906.html 开发工具: IDEA 2022.1.4 目录 目录 1. 概述 2. 实现步骤 2.1 maven导入依赖 2.2 随意代码演示(不推荐) 2.3 规范代码演示(推荐) 3. Junit相关其他注解 4. 注意事项 5. 结语 1. 概述 接触到Junit,…...

Android开发之简单控件
文章目录一 文本显示1.1 文本设置的两种方式1.2 常见字号单位类型2.2 设置文本的颜色三 视图基础3.1 设置视图的宽高3.2 设置视图的间距3.3 设置视图的对齐方式四常用布局4.1 线性布局LinearLayout4.2 相对布局RelativeLayout4.3 网格布局GridLayout4.4 滚动视图ScrollView五 按…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...