场景:晚上做稳定性压测,早上回来发现内存溢出

2022-06-08 08:29:10.273 ERROR 7 — [alina-utility-2] org.apache.catalina.core.StandardServer : Error sending periodic event
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.concurrent.FutureTask.report(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.FutureTask.get(Unknown Source) ~[na:na]
at org.apache.catalina.core.StandardServer.startPeriodicLifecycleEvent(StandardServer.java:943) ~[tomcat-embed-core-9.0.60.jar!/:na]
at org.apache.catalina.core.StandardServer.lambda$startInternal 0 ( S t a n d a r d S e r v e r . j a v a : 933 )   [ t o m c a t − e m b e d − c o r e − 9.0.60. j a r ! / : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s 0(StandardServer.java:933) ~[tomcat-embed-core-9.0.60.jar!/:na] at java.base/java.util.concurrent.Executors 0(StandardServer.java:933) [tomcatembedcore9.0.60.jar!/:na]atjava.base/java.util.concurrent.ExecutorsRunnableAdapter.call(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor S c h e d u l e d F u t u r e T a s k . r u n ( U n k n o w n S o u r c e )   [ n a : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d P o o l E x e c u t o r . r u n W o r k e r ( U n k n o w n S o u r c e )   [ n a : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d P o o l E x e c u t o r ScheduledFutureTask.run(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor ScheduledFutureTask.run(UnknownSource) [na:na]atjava.base/java.util.concurrent.ThreadPoolExecutor.runWorker(UnknownSource) [na:na]atjava.base/java.util.concurrent.ThreadPoolExecutorWorker.run(Unknown Source) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.60.jar!/:na]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: java.lang.OutOfMemoryError: Java heap space

第一反应就是把服务 dump 下来慢慢分析

进入容器,发现里面没有 jmap 命令,原因是 dockerFile 里的基础镜像使用的是 JRE

# 基础镜像
FROM openjdk:11.0-jre

上 dockerHub 寻找 JDK 镜像 dockerHub java11镜像

发现 JDK 11 镜像太大了
在这里插入图片描述
于是选择 11-jdk-oraclelinux7
在这里插入图片描述
修改 dockerFile

# 基础镜像
FROM openjdk:11-jdk-oraclelinux7
# 制作人
MAINTAINER njc
# 将工程的jar打包到镜像中
COPY target/app.jar app.jar
# 暴露的端口
EXPOSE 7001
# 镜像启动后执行的命令
ENTRYPOINT  java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -jar /app.jar

启动命令加上两个参数
-XX:+HeapDumpOnOutOfMemoryError :表示当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=/tmp/heapdump.hprof :表示生成DUMP文件的路径,也可以指定文件名称

调整容器的内存分配,使压测效果更快

在这里插入图片描述

Limits :最大值
Reservations :初始值

再次压测,内存溢出时,发现 heapdump.hprof 文件已生成
在这里插入图片描述

模糊查询 docker 容器,获取容器 id

docker ps -f name=.*user.*

复制容器里的文件到本地目录

docker cp [容器id]:tmp/heapdump.hprof /root
# docker cp 1a54f6c9011d:tmp/heapdump.hprof /root

终于 dump 下来了,接下来就是分析

java自带工具 jvisualvm,默认路径在 C:\Program Files\Java\jdk1.8.0_291\bin
分析了半天,没找到原因

转用使用 HeapHero heaphero
在这里插入图片描述
上传 heapdump.hprof,开始分析

分析第三点大对象,非常清晰,这个接口使用了 JceSecurity 做 RSA 的解密,而 javax.crypto.JceSecurity.verificationResults 这个是静态对象,不能释放,所以就 OOM 了
在这里插入图片描述

问题最终在于每次加密都创建一个静态对象,把 static 删除就 ok 了

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐