c3p0连接池内存泄漏,在重新部署Tomcat时如何处理?

6

我有这些关闭c3p0连接管理器的代码,但似乎还有一个线程没有关闭。我是有遗漏了什么吗?

Oct 11, 2016 5:12:09 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing WebApplicationContext for namespace 'dispatcherServlet-servlet': startup date [Tue Oct 11 17:11:58 PHT 2016]; parent: Root WebApplicationContext
2016-10-11 17:12:09 - [INFO ] CRMContextListener - Trying to Close
2016-10-11 17:12:09 - [INFO ] CRMContextListener - Close Success
Oct 11, 2016 5:12:09 PM      org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing Root WebApplicationContext: startup date [Tue Oct 11 17:11:44 PHT 2016]; root of context hierarchy
Oct 11, 2016 5:12:09 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: A web application registered the JBDC 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. Oct 11, 2016 5:12:09 PM     org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [C3P0PooledConnectionPoolManager[identityToken->2xjsis9j1do3mrp1m3tqb8|fb6fd9c]-DeferredStatementDestroyerThread-#0] but has failed to stop it. This is very likely to create a memory leak.

这是我的servlet监听器代码。
public void contextDestroyed(ServletContextEvent sce) {
    logger.info("Trying to Close");

    for (Object o : C3P0Registry.getPooledDataSources()) {
        try {
            ((PooledDataSource) o).close();
        } catch (Exception e) {
            logger.info("No thread was open...");
        }
    }

    logger.info("Close Success");
}

这是我的c3p0 XML配置文件:

代码如下:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="oracle.jdbc.driver.OracleDriver" />
    <property name="jdbcUrl" value="jdbc:oracle:thin:@sph-pdc-vm  1042:1521:DEV" />
    <property name="user" value="TSW" />
    <property name="password" value="TSW2015#" />
    <property name="minPoolSize" value="2" />
    <property name="maxPoolSize" value="20" />
    <property name="initialPoolSize" value="5" />
    <property name="testConnectionOnCheckin" value="true" />
    <property name="idleConnectionTestPeriod" value="100" />
    <property name="maxIdleTimeExcessConnections" value="5" />
    <property name="maxStatementsPerConnection" value="10" />
    <property name="acquireIncrement" value="1" />
    <property name="statementCacheNumDeferredCloseThreads" value="1" />
    <property name="acquireRetryAttempts" value="2" />
    <property name="acquireRetryDelay" value="2000" />
</bean>

Thanks in advance....


连接池数据源清理确实很有帮助。非常感谢!for (Object o : C3P0Registry.getPooledDataSources()) { try { ((PooledDataSource) o).close(); } catch (Exception e) { logger.info("没有线程打开..."); } } - Raguram
1个回答

2
这可能不是真正的内存泄漏,而是一个错误的警告,因为c3p0的线程需要一些时间来关闭,close()方法不等待它完成,它是异步的。所以你会收到烦人的消息。参见this github issue,感谢github上的Buğra Gedik。如果你想测试这个理论,可以在调用close()后添加一秒左右的延迟[即调用Thread.sleep(1000)],看看消息是否消失。

虽然我认为这不是你的问题,但你可能也考虑添加一些Tomcat参数,以确保尝试关闭线程总是成功的。只需添加...

<property name="privilegeSpawnedThreads" value="true" />
<property name="contextClassLoaderSource" value="library" />

查看c3p0的文档

我尝试在close()之后调用Thread.sleep(1000)。但是消息仍然存在。 - Anonymous
这实际上解决了问题,你的理论是正确的!!!我只是将时间延迟增加到3000,内存泄漏的日志就消失了!谢谢! - Anonymous
附加问题。在Tomcat中取消部署应用程序是否应该减少Perm Gen空间?因为当我尝试取消部署我的应用程序时,Perm Gen会增加2MB。而当我重新部署我的应用程序时,它会增加20MB。 - Anonymous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接