记一次OOM的排查

问题:接手了一个项目,现场性能问题颇多,top一下,主要体现在java占用内存高,mysql 占用内存,cpu高,wa值高,于是接到了一个任务,优化,见效快的那种,在优化了一些东西后,在研发环境(mysql用的从现场备份回来的数据)测试的时候发现OOM,且必现(PS:公司网络策略很严,图片都上传不了。。。)

问题排查:

1 从报错日志中,发现是在一个方法执行的时候报的错,这个功能是从别的节点同步数据,大概逻辑是每隔一分钟通过http调用获取5000条数据,然后在for里面,一次50条数据插到数据库中,报错在第一步,通过http获取数据

2 通过jstat工具查看JVM的GC情况

# 到jdk的bin目录下
cd /jdk../bin
# 获取gc的执行情况 1S采样一次,共10次
./jstat -gcutil 进程号 1000 10

发现,old去已经占用90% + ,且此时还没有发生full gc,所以怀疑是不是存在内存泄露的情况

3 顺着这个方向,在代码里面做了一些处理,不用的变量做置空处理,重新项目后发现OOM的情况依然存在

4 决定将堆dump出来,观察堆里面到底存了什么东西

#依然在jdk的bin目录下
./jmap -dump:format=b,file=/20200709.hprof 进程号

将文件down到本地,用jdk自带的工具Java VisualVM打开,发现类目录里面最多的第一是char[],第二是String,第三是PreparedStatement$ParseInfo,在char[]上右键,选择在实例视图中显示,跳转以后,选择按大小排序,发现有很多的实例大小达到了4M,总大小达到了1G,选中一个实例,在右下角引用发现是PreparedStatement的ParseInfo进行了引用,怀疑是mybatis的batchInsert操作有什么坑导致了内存泄露,在网上一番搜索后未果。

5 决定获取更多信息,于是使用VisualVM远程到研发环境监控jvm的情况,具体可参考

https://www.cnblogs.com/xifengxiaoma/p/9402497.html

通过观察发现,当执行1中的操作的时候,堆的使用内存增长的很快,但是当达到full gc的触发条件时,是可以通过full gc将内存的使用情况恢复到正常水平,所以觉得这不是内存泄露,而是内存不足导致的OOM,然后继续观察,在某次堆内存持续上升,快要达到临界点的时候发生了OOM,观察项目日志发现此时代码通过http获取了数据

结论:

 初步结论是通过http获取的数据有5000条,每条数据很大,最大的有4M数量还不少,导致堆内存被占用过高,但是通过full gc可以回收掉,所以不是内存泄露,当old区使用快要到达临界点时,又通过http获取了很多的数据,此时内存不够,且没有进行full gc 所以导致了oom

处理:

减少了每次处理的数据量,JVM使用正常。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值