记一次线上项目内存溢出排查经历

   日期:2020-05-30     浏览:259    评论:0    
核心提示:这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar运

绪言

时间会使人阅历丰富,但不是所有人都能丰富阅历,只有那些经常记录总结思考沉淀的人才会丰富。好记性不如烂笔头,况且,花了一定的功夫才研究出来的方案时间一长总是会忘的,下次再遇到还要花这些时间就很不明智了。所以催生了自己写博记录经验的想法,有不足之处还请各位前辈不吝指点!

背景

最近在项目交付测试的过程中,经常有应用在一顿操作之后界面就一直在转,最后报了无法获取数据的错误,查看日志发现有报错,其中关键点在于java.lang.OutOfMemoryError:Java heap space,jvm内存溢出,如下图

经过网上一顿搜索,发现有很多可以监测定位的方法,但是由于和自己的业务场景不合,都以失败而告终。最终尝试出一条可以解决自己问题的路径,记录下来以供下次复查。

内容提纲

环境和工具

操作系统:centos7
部署环境:docker/k8s
jdk:1.8.0_191
开发框架:springboot1.5
jvm监测工具:jvisualvm
ssh工具:SecureCRT

步骤

1、 更改Dockerfile配置

更改应用的dockerfile文件,增加java 启动参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/wch,如下:

FROM xxx.com/fcae/jre-mos:latest
MAINTAINER FAE Config Server "fae@xxx.com"
ADD ./target/task-1.0.0.jar app.jar
RUN sh -c 'touch /app.jar'
ENV TZ=Asia/Shanghai 
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV APP_NAME=task
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/wch -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

其中,-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/wch 为新增启动项,补充一下参数介绍:
-XX:+HeapDumpOnOutOfMemoryError :当应用抛出 OutOfMemoryError 时自动生成dump文件
-XX:HeapDumpPath=/home/wch :指定dump文件的存储路径(后缀是.hprof)

2、 docker构建并启动应用

构建应用并启动容器,然后复现内存溢出的场景,发现日志出现内存溢出了,但指定位置的dump文件并未生成。后研究发现,docker 构建的镜像使用的openjdk,和oracle的jdk1.8功能是不一样的,所以最后只能将应用在测试环境使用 java -jar 启动,使用上oracle的jdk,再复现内存溢出的场景,启动命令如下:

java -jar -Xmx512m -Xms256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/wch task-1.0.0.jar

3、 java -jar方式启动应用

启动后复现内存溢出场景,日志如下:

其中,Dumping heap to /home/wch/java_pid25882.hprof 指出dump文件存储到了指定的/home/wch路径下
这里的图中的hprof文件可能和下文的不一致,由于项目的内存溢出问题已解决,问题图片未留档,使用另外一种方式复现了内存溢出的场景,只是想告诉读者,在Java启动项里加上配置后,内存溢出时,会有如上图所示的hprof文件生成日志。

4、 下载dump(.hprof后缀)文件

到指定路径下下载hprof文件,下载方法有很多种,下面列出一种:
将SecureCRT的ftp会话切换到sftp会话,然后执行如下命令:

cd /home/wch 切换到dump文件存储路径
lls 列出对应自己本地存储路径下文件
get -r java_pid2134.hprof 将测试环境下的dump文件下载到本地

5、 使用jvisualvm工具装载dump文件(.hprof 后缀)

jvisualvm工具在jdk安装bin目录下,打开后 选择菜单文件 --> 装入,选择下载下来的hprof文件,打开,如下图:

6、 分析导致内存溢出的线程

在概要 --> 基本信息里可以看到 导致 OutOfMemoryError 异常错误的线程: XNIO-2 task-8
点击异常线程链接 (图中2处) ,跳转到异常线程堆栈信息,如下图,红色的线程是造成内存溢出的线程

在堆栈信息里就可以定位到导致内存溢出的具体业务类了,由该dump文件定位出 是一个查询的接口,数据量500多万,未做分页,可能是 大量数据流进内存,导致内存不足,于是重构查询逻辑加上分页,就未复现出该问题了。

7、分析导致内存溢出的类

若是想分析是哪些类导致了内存溢出,可以继续点击jvisualvm的类视图,如下图:

图中可知byte[] 类占用内存最多,61%的内存,继续往下看,可以看到JDBC的类也占了5%的内存,猜测问题可能跟数据库连接有关。

继续看byte[] 类 应用的实例,在类名上右键,在实例视图中显示,会报下图的错误:

提示是netbeans IDE 配置的内存不足,但我自己又未安装该开发工具,又是一顿艰难搜索,终于找到
解决方案。

找到jvisualvm工具的配置文件,我的路径如下:
D:\Program Files\Java\jdk1.8.0_66\lib\visualvm\etc\visualvm.conf

打开文件可以看到我的启动内存和最大内存只有100m、200m,如下图:

将 参数改成 -J-Xms1024m -J-Xmx2048m
重启jvisualvm工具,再次查看类的实例视图,发现可以正常打开了。
如下图,可以查看类的引用信息。

结论

  • 以镜像方式(docker)部署的Java应用,打包的是openjdk,可能有些Java脚本和自己本地开发使用的jdk脚本不一致,导致有些监测方法无法使用

注意事项

   暂无

参考文章

VisualVm Error记录

 
标签: 文章标签: jvm oom
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服