生产环境OOM问题

这里写自定义目录标题

问题描述:产生如下异常

java.lang.OutOfMemoryError: GC overhead limit exceeded
Sun 官方对此的定义:超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常。

【现象】如下图所示
打开Visual GC 查看JVM各个内存区的占用情况
在这里插入图片描述
Eden区的GC频率非常高,导致两个S区切换频率也高,Old区已经占满并且频繁GC,GC时间还特别长。
在这里插入图片描述
监视中可以看到,整体内存的使用量是高频率波动上涨趋势。

问题排查步骤:
1、 查看抽样器,看到热点方法是netty执行的一个select(),占用内存最大(当时处理时没截图),第二、第三分别是char[],byte[]。
2、 将网关中netty相关的代码屏蔽之后再执行,现象没有改善,排除网关的netty。之后查看引用了netty的依赖,发现框架组件component-lock中依赖的redisson有对netty的引用,其版本可能与网关的netty有冲突。
3、 屏蔽component-lock中redisson对netty的依赖后部署执行,开发环境、测试环境、UAT环境恢复稳定。于是更新到生产环境,却发现生产环境的监控图标趋势并不平稳,最终发展到如上图所示,发生OOM异常。
4、 将问题复现到开发环境。网关组件的启动参数设置为

-Xmx128m -Xms128m -Xmn32m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70

通过jmap命令将堆信息导出进行分析

jmap -dump:format=b,file=heap.bin 进程号

然后用MemoryAnalyzer打开heap.bin文件进行分析,发现手动编写的解码器产生了大量HashMap占用很大内存空间,于是升级为netty自带的解码器,问题已经解决了大半,Full GC的频率有所降低,但时间久了还是发生上面的内存溢出。继续分析。

通过top命令确定cpu占用最高的进程(排除JVM进程)

找出cpu占用最高的线程号:top -Hp 进程号 -d 1 -n 1
打印堆栈信息:jstack 线程号 > javadump.txt
把线程id 转换为十六进制:命令:echo “obase=16;线程号” |bc
在javadump.txt文件中查找得到的16进制字符串,定位到对应的堆栈

在本事例中,堆栈为

"nioEventLoopGroup-6-8" #124 prio=10 os_prio=0 tid=0x00007f4a801ec800 nid=0x68eb waiting for monitor entry [0x00007f4a7c0c6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at javax.crypto.JceSecurity.getVerificationResult(JceSecurity.java:171)
	- waiting to lock <0x00000000fb2c1210> (a java.lang.Class for javax.crypto.JceSecurity)
	at javax.crypto.Cipher.getInstance(Cipher.java:653)
	at com.eg.egsc.scp.smartchargegateway.util.RSAUtils.decryptByPrivateKey2(RSAUtils.java:194)
以下省略

定位到是项目代码中RSA解密方法导致的内存溢出。原来的代码如下:

Cipher.getInstance("RSA", new org.bouncycastle.jce.provider.BouncyCastleProvider());

修改后的代码如下,将BouncyCastleProvider类声明为静态变量bcp

Cipher.getInstance("RSA", bcp);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值