使用Oracle JDBC驱动程序12c的Tomcat 7上的内存泄漏 - oracle.jdbc.driver线程无法停止

时间:2014-10-03 14:22:16

标签: java tomcat jdbc

我有一个部署到Tomcat 7.0.54的Web应用程序,它使用数据源连接到Oracle 11g数据库。数据源在META-INF/context.xml中配置,并且我已在<tomcat-install-dir>/lib中放置了ojdbc7.jar。我使用JNDI查找来检索我存储在单例中的数据源,以便每个DAO类都可以使用它。

一切都按预期工作,但是当我取消部署应用程序时(通过Tomcat管理器应用程序),我在日志中看到:

Oct 03, 2014 3:06:55 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/myapp] appears to have started a thread named [oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser] but has failed to stop it. This is very likely to create a memory leak.
Oct 03, 2014 3:06:57 PM org.apache.catalina.startup.HostConfig undeploy
INFO: Undeploying context [/myapp]

当我调试时,我可以看到一旦访问数据库就会创建这个线程(通过数据源)。

我的数据源配置:

<Context antiResourceLocking="false">
    <Resource name="jdbc/myapp" auth="Container" 
        type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" 
        maxActive="20" maxIdle="10" maxWait="-1"
        username="myuser" password="mypass"
        url="jdbc:oracle:thin:@myserver:1521:mysid"
        removeAbandoned="true" removeAbandonedTimeout="10" logAbandoned="true"
        validationQuery="SELECT 1 FROM DUAL"   
        testOnBorrow="true" testOnReturn="true" testWhileIdle="true"  
        timeBetweenEvictionRunsMillis="1800000" numTestsPerEvictionRun="3"  
        minEvictableIdleTimeMillis="1800000"
    />
</Context>

修改

进一步调查显示,无论在应用程序(或servlet)初始化期间是否访问数据源,都会出现问题。

实际上,只有在使用12c版本的Oracle JDBC驱动程序(ojdbc6.jar或ojdbc7.jar)时,才会创建有问题的线程,因此只存在问题。

如果我恢复使用ojdbc6.jar的11.2.0.4版本,则永远不会创建线程,并且永远不会出现内存泄漏警告。

我应该降级JDBC驱动程序(如https://stackoverflow.com/a/9177263/4105953中所述)吗?

3 个答案:

答案 0 :(得分:1)

我找到了关于这个主题here的冗长讨论。结论是它创建了一个固定大小的内存泄漏,即后续的重新部署不会增加内存泄漏。
我没有Oracle Support访问权限,但讨论中提到的错误ID是16841748(2013年5月,现在可能已经解决)。

一种可能的解决方法是在Tomcat通过配置为&#34; load-on-startup&#34;的自定义servlet启动时实际使用数据源一次(获取连接,执行虚拟查询,关闭连接)。在tomcat/conf/web.xml。这应该启动您的web-app的类加载器范围之外的Oracle驱动程序线程(另请参阅有关驱动程序线程的FAQ),从而防止&#34;固定大小的内存泄漏&# 34。

请注意,MySQL JDBC驱动程序存在类似问题,但有decent solution。对于最新版本的Oracle JDBC驱动程序(我不知道),可能存在这样的解决方案。

答案 1 :(得分:0)

这是正常的,当您在Tomcat中进行热部署时会发生这种情况。它通常不会在生产中导致任何问题,因为您通常不会在生产中热部署更新,只需停止并重新启动服务器。

答案 2 :(得分:-1)

仅使用Oracle JDBC驱动程序(oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser)不会发生此问题。

如果任何第三方依赖项启动守护程序线程以执行某些任务,那么在停止Tomcat时也会为它们发送警告消息。

此外,Tomcat 8.5.X版本存在此问题。

解决方案: 我发现解决方案是获取当前线程的线程组并中断它。它将确保在关闭Tomcat之前,所有它的守护程序线程都会被杀死。

下面的代码应添加到&#34; contextDestroyed&#34;方法 ThreadGroup threadGroup = Thread.currentThread()。getThreadGroup(); threadGroup.interrupt();