3

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)

 1 year ago
source link: https://blog.51cto.com/fengyege/5919688
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、问题场景

在线上运行的程序,有一天突然前端响应缓慢,但是后台日志依旧还在正常输出。针对这种情况,本篇博客主要是进行问题解决的过程说明。

二、问题环境

Centos

proxool

0.9.0RC3

三、问题原因

1. 使用top命令查看进程情况

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_问题解决

2. 使用jstat命令查看当前GC情况

jstat -gcutil 13062 5000

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_问题解决_02

从上图可以看出,现在项目是处于频繁GC的状态,内存基本都被占满了。

3. 使用jmap命令打印当前存活的最大20个对象

jmap -histo:live 13062 | head -20
问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_tomcat_03

从上图可以看到,目前是数据库相关的类占用了比较大的空间。其中有proxool,这个时候猜测是因为proxool的问题导致的。

4. 使用jmap保存当前堆栈信息

jmap -dump:format=b,file=heap-dump.bin 13062

5. 使用MAT工具进行head.dump的分析

将第4步导出的堆栈信息,使用MAT工具打开,打开之后,进行分析,分析结果如下:

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_堆栈_04

从图中,可以知道,Finalizer占用了最大的空间,达到了2.9GB。

6. 使用jstack命令获取进程的堆栈信息

之后,我们使用以下命令将该进程的堆栈信息dump下来,如下:

jstack 13062 > 13062 _error.log

并搜索Finalizer字眼,结果如下:

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_问题解决_05

7. 锁定问题

这个就是比较著名的​​proxool​​​内存泄露问题,在​​JVM​​​回收​​WrappedConnection​​​对象时,由于代理类重写了​​finalize​​​方法,​​WrappedConnection​​​方法被丢进引用队列等待​​finalizer​​​线程执行​​finalize​​​方法,​​finalize​​​本身没有额外的实现,但是代理类在执行该方法之前会做一个​​isClose​​​的判断,而​​jdbc oracle​​​的实现类则使用了​​synchronize​​​修饰了​​isClose​​​,导致业务逻辑从池里拿出来该连接使用的时候会与​​finalize​​​线程竞争该锁,一旦业务逻辑处于繁忙状态则​​finalizer​​线程执行的频率大大减小,此时在队列中的引用依然存在,对象仍然会在堆中存活。

四、解决方案

既然知道了原因,那么覆写​​org.logicalcobwebs.proxool.WrappedConnection​​类,添加以下代码:

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_tomcat_06

然后重新编译提交到项目中,并重启。

升级补丁之后,重启项目。到了第二天,再将堆栈信息dump下来查看,已经没有Finalizer的内存占用了。问题得到解决。

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_tomcat_07

本篇博文主要是记录此次解决过程中使用的各种命令,熟悉使用可以解决很多问题。

七参考链接

 ​解决proxool连接oracle内存溢出的问题​​​ ​压测调优之遇到的proxool问题​

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;如果有好的讨论,可以留言;

如果想继续查看我以后的文章,可以点击关注 可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!

问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_JVM_08
问题解决系列:记录一次Java程序内存泄露的解决过程(proxool内存泄露)_堆栈_09

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK