当前位置: 首页 > news >正文

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

![在这里插入图片描述](https://img-blog.csdnimg.cn/447af6724a804de4b00fcd6f11afcb90.png

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文件
在这里插入图片描述
在这里插入图片描述

  1. 查看相应的堆栈信息, 以及方法入栈/出栈等信息, 系统属性 显示线程 等确定代码异常位置
  2. 查看类信息, 找出类创建数量多的类, 是否有自己写的相关类信息,进行代码定位
代码解决方案
  1. 升级groovy版本为2.4.8或以上版本
  • 1. java SPI提供的接口方式
@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;}}
}
  • 2.groovy shell方式
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节点&#xff0c;用户名默认为root&#xff0c;密码默认为000000。连接上之后&#xff0c;使用linux命令修改节点主机名。 [rootcontroller ~]# hostnamectl set-hostname controller [rootcontroller …...

Java 运算符与类型转化

Java 运算符与类型转化 1 算术运算符 Java中的算术运算符主要有&#xff08;加&#xff09;、-&#xff08;减&#xff09;、*&#xff08;乘&#xff09;、/&#xff08;除&#xff09;、%&#xff08;求余&#xff09;&#xff0c;它们都是二元运算符。 2 自增和自减运算…...

《C++ Primer Plus》第18章:探讨 C++ 新标准(2)

移动语义和右值引用 现在介绍本书前面未讨论的主题。C11 支持移动语义&#xff0c;这就提出了一些问题&#xff1a;为何需要移动语义&#xff1f;什么是移动语义&#xff1f;C11 如何支持它&#xff1f;下面首先讨论第一个问题。 为何需要移动语义 先来看 C11 之前的复制过程…...

QML定时器

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

第三章 opengl之纹理

OpenGL纹理纹理环绕方式纹理过滤多级渐远纹理加载和创建纹理stb_image.h生成纹理纹理的应用纹理单元纹理 用stb_image.h库&#xff0c;原先用SOIL库也可以实现。 可以为每个顶点添加颜色来增加图形的细节。但是想得到一个真实的图形&#xff0c;需要足够多的顶点&#xff0c;…...

【Flink】FlinkSQL中执行计划以及如何用代码看执行计划

FilnkSQL怎么查询优化 Apache Flink 使用并扩展了 Apache Calcite 来执行复杂的查询优化。 这包括一系列基于规则和成本的优化,例如: • 基于 Apache Calcite 的子查询解相关 • 投影剪裁 • 分区剪裁 • 过滤器下推 • 子计划消除重复数据以避免重复计算 • 特殊子查询重写,…...

从业者必读,一篇文章轻松掌握DevOps核心概念和最佳技能实践!

文章目录前言一. DevOps的定义及由来二. DevOps的价值三. devops工具有哪些3.1 devops工程师的硬实力3.2 devops工程师的软实力总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文是对DevOps的总结&#xff0c;一篇文章告诉你什么是DevOps. 对很多…...

2023爱分析·一体化HR SaaS市场厂商评估报告:北森

目录 1.研究范围定义 2. 一体化HR SaaS市场分析 3.厂商评估&#xff1a;北森 4.入选证书 1.研究范围定义 研究范围 伴随数字化转型走向深入&#xff0c;企业人力资源数字化也进入快速发展阶段&#xff0c;人力资源的价值也得到了重新审视和定义。政策层面&#xff0c;《…...

JAVA练习67-二叉树的中序遍历

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、题目-二叉树的中序遍历 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 3月3日练习…...

【JeecgBoot-Vue3】第1节 源码下载和环境安装与启动

目录 一. 资料 1. 源码下载 2. 官网启动文档 二、 前端开发环境安装 2.1 开发工具 2.2 前后端代码下载 2.3 前端启动 Step 1&#xff1a;安装nodejs npm Step 2&#xff1a;配置国内镜像&#xff08;这里选阿里&#xff09; Step 3&#xff1a;安装yarn Step 4&…...

WebAPI

WebAPI知识详解day11.Web API 基本认知作用和分类什么是DOM&#xff1f;DOM树的概念DOM对象2.获取DOM对象通过css选择器获取dom对象通过其他方法获取dom3.设置/修改DOM元素内容方法1. document.write() 方法方法2. 对象.innerText 属性方法3. 对象.innerHTML4.设置/修改DOM元素…...

Shell命令——date的用法

date命令可以用来显示或设定系统的日期与时间。 一、显示系统的日期与时间 &#xff08;1&#xff09;如果date命令后面不加任何参数&#xff0c;则会按照固定的格式显示时间信息&#xff1a; 星期几 月份 日 时:分:秒 时区 年xjhubuntu:~/iot/tmp$ date Fri Mar 3 16:56:4…...

XSS跨站脚本

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

【强烈建议收藏:MySQL面试必问系列之慢SQL优化专题】

一.知识回顾 学习本篇文章之前呢&#xff0c;我们可以先看一下【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】&#xff0c;看完这篇文章再来学习本篇文章可谓是如虎添翼。好的&#xff0c;那我们也不讲太多的废话&#xff0c;直接开始。 二.如何做慢SQL查询优化呢&…...

windows,liunx,java实现apk解压,去签名、重新签名,重新打包apk

背景&#xff1a;由于项目需要&#xff0c;需要将apk包加入服务端返回的静态资源文件到apk中&#xff0c;形成离线apk包供下载安装。经过调查研究&#xff0c;决定使用apktool实现。关于apktool的资料可以参考 https://blog.csdn.net/quantum7/article/details/124060620 htt…...

【Linux】进程信号

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;信号入门&…...

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&#xff0c;…...

Android开发之简单控件

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

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...