记一次(netty性能压测)的JVM 大对象 排查

手写了一个netty的client 对 我们的消息服务进行性能压测。

1、client端的逻辑是,利用netty的EventLoopGroup线程池进行模拟用户的connect连接上之后,由于服务端的心跳的机制,如果用户的channel在12分钟内没有进站事件发生,那么服务端就会主动断开链接。

        由于我们只有用户连接上服务端之后才可以发送消息,所以要发送两次消息,connect的时候发送一个上线通知。后续发送业务消息。

      所以客户端另起一个定时线程池,考虑到测试机器的性能,核心线程数设置为20。启动2分钟后开始执行,每间隔2分钟执行一次。(jvm的-Xms4g -Xmx4g 时能测试到连接数为12w左右)。但是由于2分钟执行一次,导致服务端的cpu压不上去。

       所以减少时间间隔,修改为每7s中执行一次,用户发消息的逻辑。

2、目前7s中执行一次发消息的逻辑,连接数到达3w的时候,发现jvm的堆内存已经满了。此时old  区占用整个堆内存的99%,如果继续压测会导致OOM。所以此时问题就来了。

        问题:

                为什么7分钟的时候old区会正常,但是7s的时候,到达2w连接数的时候就会导致old爆满?此时服务端的cpu也会降下来。

        现象:

利用 jmap -heap pid查看内存情况

1、首先我们的项目用的是G1垃圾收集器,此时堆内空间并不是连续的,而是一个个的region。年轻带、幸存者区、老年代,都不是固定的。G1的目标就是减少Full GC,而此时,我们的服务基本停掉,一直不停的在执行Full GC。而到达这种状态的时候,我们的 S区E区region为零,而老年代几乎占据了所有的region----------------------> 说明此时存在大对象,导致了很多的内存碎片,所以导致新对象没有进入E区S区直接进入了Old区,所以导致Old区内存不够用,就会晋升失败。

2、此时执行Full GC的时候的gc.log 一直显示 晋升失败

 

利用 jstat -gc pid 查看 gc 情况

3、发现full gc 次数频率很高,ygc频率更高,所以说明,每进来一个对象,就直接ygc了,然后因为old区内存不够用,所以就会直接full gc。

        定位:

 既然问题定位到了有大对象,此时有两种解决方案:

        第一种:调大region的大小,让大对象不再是大对象。通过(XX:G1HeapRegionsize 设定

        第二种:排查代码

第一种方法,明显就是暂时的解决方案,所以我们可以用第二种。

        步骤:

1、首先用 jmap -histo pid | head -20 查找前20名大对象。 或者 jamp -histo:live pid | head -20 查找前20名存活对象。

2、打印dump 文件 : jmap -F -dump:live,file=jmap.hprof [PID]

3、用eclipse 的 mat 进行分析。

4、根据dominator_tree找出大对象。

 5、分析具体业务逻辑代码。 

我的问题,是由于我们代码中有个,阻塞队列<200的话,就不删除ConcurrentHashMap当中的元素,而每次删除ConcurrentHashMap中的元素时,每次只删除1w条。所以就会在ConcurrentHashMap中慢慢累加元素,就会导致占用内存越来越多。导致大量的对象被ConcurrentHashMap引用无法释放,最后导致OOM。

所以我们netty的server的性能瓶颈就在这里,这也是特殊情况,因为我的客户端是以一定的速率进行发送消息的。而实际情况,用户发消息是又快又慢的。如果我们的量级真的达到了这种,可以适当调大线程池的核心线程数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值