大海捞针-记一次排查内存溢出事件

        据实施人员交代,这个巨型项目在2020-2021年平稳运行了一年,元旦之后,频繁报内存溢出,有时几天一次,有时一天几次,完全摸不到规律。而且堆内存已设置最大4G。OK,开整!

        首先,堆转储文件已不可得,在weblogic增加jvm参数,下次OOM时即可获得堆转储文件。

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath

        一边等问题复现,一边从程序的角度排除。程序有无定时任务?有!但挨个看了,quartz的定时任务中,并不存在会导致内存溢出的代码,至少看起来是这样。然后看Oracle的Job,执行的存储过程有无问题,依旧没有问题。

        从日志方面排查,weblogic日志中,有很多报线程超时未处理完的错误。当然,这种日志只能提供参考,并不一定是内存溢出的根本原因。亦可能内存将满之后,其它线程在处理时,JVM无法GC,没有空间创建对象,而导致线程一直阻塞中。

more than the configured time (StuckThreadMaxTime) of "600" seconds. Stack trace:
	java.lang.Object.wait(Native Method)
	java.lang.Object.wait(Object.java:485)
	java.io.ObjectStreamClass$EntryFuture.get(ObjectStreamClass.java:369)
	java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:303)
	java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:545)
	java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1599)
	java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1494)
	java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1748)
	java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1327)
	java.io.ObjectInputStream.readObject(ObjectInputStream.java:349)
	net.XXXXXXXXXX.YYYYYY.cached.cache.Caches.unserialize(Caches.java:108)

        再看项目本身日志,记录信息也有限,而且打印的堆栈也不一定是内存泄漏的方法。

[ERROR][2022-01-01 12:32:54][SYSTEM]java.lang.OutOfMemoryError: GC overhead limit exceeded

        然后连续几天观察jvisualvm工具的信息,发现堆内存占用在0.3G到1.5G以30分钟间隔,呈周期性升降。

 

         完全找不到规律,看来只能等事件发生了。

        果然,11月13号(上一次是11月2号),终于出现OOM错误,直接取文件观之(5G之巨)。

         首先,采用JVM自带的jvisualvm工具导入,但一直加载不了。然后采用IBM HeapAnalyzer工具,甚至在启动工具时加了参数 Java -xmx8000m -jar *.jar,加载了十分钟,进度定格在59%,然后直接无响应状态了,无奈又作罢。

        接着,换了一款收费工具JProfiler,这款工具那是相当强大,不到3分钟就加载好了堆转储文件。

        看上面几张关键截图,其实问题已经很明显了,几个自定义RowSet对象竟然占据了数G的内存空间。结合源码分析,发现是一个SQL中查出来的数据量达66万行之大。之前正常,为何忽然巨大呢?因为三方直连项目的数据库,执行了错误的脚本,生成了巨量的表数据,导致查询过载,rowset对象在put数据时,内存溢出。

         给现场支方案:1、停止三方脚本运行;2、删除重复数据。

--去除重复数据脚本
--1.全量
create table AAA_BACK as select * from AAA;
--2.临时
create table AAA_TEMP as select * from AAA where SCSPF_NO in (select min(SCSPF_NO) from scspfmst group by org_no,pla_no,crw_no,SCSFT_DAT,scsft_no);
--3.全删
truncate table AAA;
--4.复制
insert into AAA select * from AAA_TEMP;
commit;
--5.去除
drop table AAA_TEMP;
--6.查验
select * from ( select count(1) as count,SCSFT_DAT from AAA group by SCSFT_DAT );

        其实,排查的过程并不尽如上面那么简单和直接,其中碰到了不少钉子,走了一些弯路,包括增加对JVM底层的学习等,最终的结果还是好的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值