Oracle驱动程序内存泄漏 - Tomcat

时间:2012-12-07 00:02:30

标签: java oracle java-ee tomcat jndi

我们正在使用tomcat-7.0.33。 Spring 3.0.1和JPA使用tomcat JNDI数据源。使用ojdbc6.jar(最新)后端的Oracle 10g。

当我们尝试取消部署应用程序时,某些Oracle类似乎正在泄漏。我在使用较旧的ojdbc14.jar驱动程序时没有看到这一点,但我们无法使用这些驱动程序,因为我们正在迁移到需要更新驱动程序的Oracle 11g。我猜这是Oracle驱动程序中的一个错误?有什么办法可以清理这些资源吗?我试过关闭数据库连接池和其他东西无济于事......

不使用Tomcat的连接池会更好吗?我们宁愿让服务器连接到数据库,但如果需要我们可以自己做...

服务器控制台显示:

17505 INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - 为持久性单元'myManager'关闭JPA EntityManagerFactory 17515 INFO org.apache.tiles.access.TilesAccess - 删除上下文的TilesContext:org.springframework.web.servlet.view.tiles2.SpringTilesApplicationContextFactory $ SpringWildcardServletTilesApplicationContext 2012年12月6日下午6:41:29 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks 严重:Web应用程序[/ myApp]使用[java.lang.ThreadLocal]类型的键创建了一个ThreadLocal(值[java.lang.ThreadLocal@1468544]),类型为[java.lang.Class](值[类oracle.sql.AnyDataFactory])但在Web应用程序停止时无法删除它。线程将随着时间的推移而更新,以避免可能的内存泄漏。 2012年12月6日下午6:41:29 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks 严重:Web应用程序[/ myApp]使用[java.lang.ThreadLocal]类型的键创建了一个ThreadLocal(值[java.lang.ThreadLocal@d73b31]),类型为[java.lang.Class](值[类oracle.sql.TypeDescriptorFactory])但在Web应用程序停止时无法将其删除。线程将随着时间的推移而更新,以避免可能的内存泄漏。 2012年12月6日下午6:41:29 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks 严重:Web应用程序[/ myApp]使用[java.lang.ThreadLocal]类型的键创建了一个ThreadLocal(值[java.lang.ThreadLocal@13​​aae39]),类型为[java.lang.Class](值[类oracle.sql.TypeDescriptorFactory])但在Web应用程序停止时无法将其删除。线程将随着时间的推移而更新,以避免可能的内存泄漏。 2012年12月6日下午6:41:29 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks 严重:Web应用程序[/ myApp]使用[java.lang.ThreadLocal]类型的键创建了一个ThreadLocal(值[java.lang.ThreadLocal@18443b1]),类型为[java.lang.Class](值[类oracle.sql.AnyDataFactory])但在Web应用程序停止时无法删除它。线程将随着时间的推移而更新,以避免可能的内存泄漏。 2012年12月6日下午6:41:34 org.apache.catalina.startup.HostConfig deleteRedeployResources 信息:取消部署上下文[/ myApp]

我尝试添加ContextListener来手动关闭我们的DBCP连接,但这没有帮助。

InitialContext initial = new InitialContext();

DataSource ds = (DataSource) initial.lookup("java:/comp/env/jdbc/myDS");

if (ds.getConnection() == null) {
    throw new RuntimeException("I failed to find the datasource");
}

LOG.debug("Found datasource.  Closing...");
BasicDataSource bds = (BasicDataSource) ds;

bds.close();

2 个答案:

答案 0 :(得分:9)

想出了问题...... Toni有一个很好的建议(但取消注册驱动程序意味着当应用程序重新加载驱动程序时不再可用!)。

在我们的案例中,我们意外地将ojdbc6.jar与我们的Web应用程序AND包含在Tomcat / lib目录中。这可能导致Tomcat使用我们的类加载器来创建对象。因此,当我们的应用程序被卸载时,Tomcat的DBCP池仍然在我们的应用程序中有类的开放句柄。

从我们的WEB-INF / lib中删除ojdbc6.jar解决了这个问题。

答案 1 :(得分:0)

在监听器中,您还必须取消注册JDBC驱动程序(即ojdbc5.jar或您正在使用的内容)。

请参阅this SO问题以获取代码段。