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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26180770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:27:14  来源:igfitidea点击:

Memory leak on Tomcat 7 with Oracle JDBC drivers 12c - oracle.jdbc.driver thread failed to stop

javatomcatjdbc

提问by finchie

I have a web app deployed to Tomcat 7.0.54 that uses a datasource to connect to an Oracle 11g database. The datasource is configured in META-INF/context.xmland I've placed ojdbc7.jar in <tomcat-install-dir>/lib. I use a JNDI lookup to retrieve the datasource which I store in a singleton so that each DAO class can use it.

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

Everything works as expected, however when I undeploy the application (via Tomcat manager app) I see in the logs:

一切都按预期工作,但是当我取消部署应用程序(通过 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]

When I debug I can see this thread gets created as soon as the database is accessed (via the datasource).

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

My datasource config:

我的数据源配置:

<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>

EDIT

编辑

Further investigation has revealed that the issue occurs whether or not the datasource is accessed during application (or servlet) initialisation.

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

In actual fact, the problematic thread is only created, and thus the issue only exists, when using the 12c versions of Oracle's JDBC drivers (either ojdbc6.jar or ojdbc7.jar).

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

If I revert to using the 11.2.0.4 version of ojdbc6.jar the thread is never created and the memory leak warning never appears.

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

Should I downgrade JDBC driver (as suggested in https://stackoverflow.com/a/9177263/4105953)?

我是否应该降级 JDBC 驱动程序(如https://stackoverflow.com/a/9177263/4105953 中的建议)?

回答by vanOekel

I found a lengthy discussion about the subject here. The conclusion is that it creates a "fixed size memory leak", i.e. subsequent redeploys will not increase the memory leak.
I do not have Oracle Support access, but the bug ID mentioned in the discussion is 16841748 (May 2013, might be solved now).

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

A possible workaround is to actually use the datasource once (get connection, do dummy query, close connection) when Tomcat is started via a custom servlet that is configured to "load-on-startup" in tomcat/conf/web.xml. This should start the Oracle driver thread(s) (see also the FAQabout driver threads) outside of the scope of the class-loader of your web-app, thus preventing the "fixed size memory leak".

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

Note that a similar issue exists for the MySQL JDBC driver but has a decent solution. Such a solution may exist for a recent version of the Oracle JDBC driver (I don't know).

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

回答by Triton Man

This is normal, it happens when you hot deploy in Tomcat. It will not cause you any problems normally in production because you don't generally keep hot deploying updates in production, you just stop and restart the server instead.

这是正常的,在Tomcat热部署时会发生。它通常不会在生产中给您带来任何问题,因为您通常不会在生产中保持热部署更新,您只需停止并重新启动服务器即可。

回答by subrat patra

This problem doesn't happen only with Oracle JDBC driver (oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser).

这个问题不仅仅发生在 Oracle JDBC 驱动程序 (oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser) 上。

If any of the 3rd party dependency starts a daemon thread for carrying out some task, then while stopping the Tomcat logs Warning message for them also.

如果第 3 方依赖项中的任何一个启动了一个守护线程来执行某些任务,那么在停止 Tomcat 的同时也会为它们记录警告消息。

Also, this problem exists with Tomcat 8.5.X versions.

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

Solution: What i found as a solution is to get the Thread Group for the current thread and interrupt it. It will make sure that before shutting down the Tomcat all it's daemon threads are killed.

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

below code should be added to the "contextDestroyed" method ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); threadGroup.interrupt();

下面的代码应该添加到“contextDestroyed”方法 ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); threadGroup.interrupt();