【JAVA】记一次典型jvm内存泄漏

   日期:2020-08-20     浏览:93    评论:0    
核心提示:一、问题概述在持续十分钟的压力测试中,单机QPS从8000陆续降低至3000的过程中发现的内存泄漏。先看一下压测计算的数据:首先是被压测的机器:机器配置:4核8G 单机预计QPS:8000左右,不超过9000 平均响应时间:12~13ms发起压测的执行机:设置单机并发数:60 执行机数量:2台由此可以计算出进行压测的QPS数据:平均响应时间为12ms,单机60的并发数,则单机的最高QPS为 60/0.012 = 5000 左右设置持续上涨4分钟,达到峰值,则可得出:

目录

一、问题概述

二、发现问题

三、解决问题

一、问题概述

在持续十分钟的压力测试中,单机QPS8000陆续降低至3000的过程中发现的内存泄漏。

首先看一下压测计算的数据:

被压测的机器:

  • 机器配置:4核8G
  • 单机预计QPS:8000左右,不超过9000
  • 平均响应时间:12~13ms

发起压测的执行机:

  • 设置单机并发数:60
  • 执行机数量:2台

由此可以计算出进行压测的QPS数据:

平均响应时间为12ms,单机60的并发数,则单机的最高QPS为 60/0.013 = 4600 左右

设置持续上涨4分钟,达到峰值,则可得出:

  • 刚开始时并发量为:60 / 4  *2 = 30 的并发量,QPS = 30/0.013 = 2300
  • 持续4min后:慢慢上涨到60*2的并发量,峰值 QPS = 120 / 0,013 = 9230

压力合理,可以缓慢达到压力的峰值并维持压力。

二、发现问题

整个压测过程分为2步,每步压测5分钟。压测完成后,查看压测报告:

首先是jmeter产出的报告:

 看上去没有问题,达到了预期的效果,但是当对该机器进行第二次压测的时候,发现它的QPS已经下降了30%

第二次压测产出的报告:

 这一次就有些困惑了,讲道理两次相同条件的压测结果差距不应该这么大,绝对是哪个地方有问题,导致qps上不去,像这种情况,多半是JVM的问题。

于是使用jdk自带的jvm监控工具对压测过程进行了监控。

将服务器重启一次,继续进行两步压测,这次从监控中直接看到了问题:

第一次报告:

 GC时间报告:

很明显,jvm的状态是有问题的:

  1. 第一张图中的堆内存使用量居然下不来,说明了内存无法被回收,说明了存在内存泄漏的问题。 
  2. 第二张图中显示老年代做GC的时间并不长,这应该是应该有的现象,这也是为什么本次压测QPS能到预期值

第二次报告:

GC时间报告:

 看似JVM已经完成了GC,但是仔细看它的GC时间,老年代的GC整整持续了2分钟,这其实是不正常的。

这个时候打开JVM的内存选项,查看了老年代的jvm情况,发现它有整整2个G的内存无法被回收,而我这台机器总共才8个G。

(虽然jvm的老年代图弄丢了,但是从上面的图可以也可以看出来,它是有几个G的内存没有被回收的)

后面当我再对其进行压力测试,它的QPS直接降到了3000左右。而它的老年代GC时间一直在变长。

 

三、解决问题

上面已经找到了问题的原因,后面发现代码问题就很简单的

本项目是一个网关项目,内部有个linkHashMap需要存放某些数据,而该map内部做了舱壁限制了总map的size。但是linkHashMap是线程不安全的,代码中并没有对它的put操作进行加锁处理,导致它的内存不断膨胀,存放的数据不断的放入老年代,最后无法被老年代回收。

代码优化完成后,对它进行长时间的压测,查看它产出的报告:

这就很合理了,FullGC之后内存就降下来了,QPS又回到了8000。

为了测试它的稳定性,后续对它进行了持续两天的压力测试,没有出现性能问题。

 

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

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

13520258486

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

24小时在线客服