解决proxool连接oracle内存溢出的问题

Proxool是一个很优秀的开源连接池。我曾经比较过dbcpc3p0 和 proxool 这三个连接池,阅读和分析它们的代码。相比之下,proxool 用了cglib,其源码显得相当简洁优雅。 但是很不幸,在这一次,内存泄漏的帐要算在它头上。 我们使用的是proxool 的0.9.1的版本,环境是Oracle JDBC5 + IBM JDK5。

0.9.1版本是proxool 的最新版本。我们有一个应用据称运行以来,就一直处于内存溢出的阴霾之中。追赶数据时的某些巨忙的系统可能会一天内死好些次,甚至达十几次。不得不采用一些监控脚本定时重启。去年12月我接手以来,也被这个问题困扰,最糟糕的时候甚至某些硬件设施很好的部署实例的多达50+GB的堆也能在一天之内吃光。

出错的原因很简单,proxool使用了cglib,它用WrappedConnection代理实际的Conneciton。在运行WrappedConnection的方法时,包括其finalize方法,都会调用Conneciton.isClosed()方法去判断是否真的需要执行某些操作。不幸的是Oracle JDBC中的这个方法是同步的,锁是连接对象本身。于是, Finalizer线程回收刚执行过的WrappedConnection对象时就总会与还在使用Connection的各个工作线程争用锁。

贴一张简单的图,你就懂了:
thread_blocked_2

解决方案是在WrappedConnection.java的第114行,做一点小小的改动,在调用的方法为finalize方法时,不要去掉isClosed()方法。事实上,WrappedConnection#finalize()方法的调用与Connection根本没啥关系。Oracle JDBC本身没有实现finalize()方法,是cglib代理的对象自己生成了一个finalize()方法而已。
修改前的114行:

if (proxyConnection != null && proxyConnection.isReallyClosed()) {

修改后的114行:

if (proxyConnection != null && !concreteMethod.getName().equals(FINALIZE_METHOD) && proxyConnection.isReallyClosed()) {

点此查看sourceforge上的完整的WrappedConnection.java

效果是很明显的。一方面,内存消耗明显降低。之前,所有的部署实例都会隔段时间就当掉,某些部署实例的52G的堆都会溢出!现在,系统再忙其堆大小也基本上在原来那个设得老大的Xms参数之下。 第二方面,吞吐量忽然提高了许多,没有烦人的回收线程(其优先级要高点)的干扰,当然应该要跑得更快些。

感兴趣的朋友可以下载我这里提供的jar包(-target 1.5),(源码是直接从官网下的proxool-0.9.1-source.zip)。这个jar包也解决了ProxoolDataSource在Spring中作为bean配置时有三个属性(maximumConnectionLifetime,houseKeepingSleepTime,overloadWithoutRefusalLifetime)不能注入的问题。详细请看这篇博文

下载 proxool-0.9.1

也可以应用patch自己编译一个。patch我上传到Bug页面了,请去那下载。


转自:http://blog.xiping.me/2011/04/proxool-memory-leak.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
proxool.0.9.1基础上做了修改。 改jar名称为:proxool-0.9.1.1,主要修改为以下3点: 1.解决不能Unregister jdbc driver的内存泄露问题。 十二月 02, 2013 8:19:43 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc SEVERE: The web application [/xxx] registered the JDBC driver [org.logicalcobwebs.proxool.ProxoolDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 十二月 02, 2013 8:19:43 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc SEVERE: The web application [/xxx] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 十二月 02, 2013 8:19:43 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc SEVERE: The web application [/xxx] registered the JDBC driver [oracle.jdbc.OracleDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 2.解决housekeeper内存泄露问题 3.解决spring配合时,只能在spring的定义中以bean方式加载proxool问题。(使用servlet方式加载也可以,只是在启动时报错) 加载方式修改为: xmlFile /WEB-INF/conf/proxool.xml org.logicalcobwebs.proxool.configuration.ListenerConfigurator 与spring配合使用时,本加载需要放在spring前面 org.logicalcobwebs.proxool.configuration.ListenerConfigurator org.springframework.web.context.ContextLoaderListener 4.修正了proxool在多线程环境下的的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值