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

3 篇文章 0 订阅
2 篇文章 0 订阅

目录

一、问题概述

二、发现问题

三、解决问题


一、问题概述

在持续十分钟的压力测试中,单机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. 第二张图中显示Scavenge做GC的时间并不长,这应该是应该有的现象,这也是为什么本次压测QPS能到预期值

第二次报告:

GC时间报告:

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

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

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

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

 

三、解决问题

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

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

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

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

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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值