Web 应用程序似乎启动了一个名为 \[Timer-0\] 的线程,但未能停止它

新手上路,请多包涵

我正在使用 Spring Boot 1.5.9.RELEASE + Java 8 + Tomcat 9 + Jersey + Oracle 并且我的应用程序已计划方法定义如下:

 @Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}

工作类别:

 @Component
public class ClearCacheJob {

    @Scheduled(fixedRate = 3600000, initialDelay = 10000)
    public void clearErrorCodesCache() {
        try {
            logger.info("######## ClearCacheJob #########");
        } catch (Exception e) {
            logger.error("Exception in ClearCacheJob", e);
        }
    }

}

我还有一个类来注销 Oracle 驱动程序,如下所示:

 @WebListener
public class ContainerContextClosedHandler implements ServletContextListener {

    private static final Logger logger = LoggerFactory.getLogger(ContainerContextClosedHandler.class);

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        logger.info("######### contextInitialized #########");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        logger.info("######### contextDestroyed #########");
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error deregistering driver %s", driver), e);
            }

        }
    }

}

但是在停止 Tomcat 时出现以下错误:

 WARNING [Thread-11] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [hai]
appears to have started a thread named [Timer-0] but has failed to stop it.
 This is very likely to create a memory leak. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 java.lang.Object.wait(Unknown Source)
 java.util.TimerThread.mainLoop(Unknown Source)
 java.util.TimerThread.run(Unknown Source)

为什么会出现此错误,我该如何解决?

原文由 Mahmoud Saleh 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 3.1k
1 个回答

我想与此问题的根本原因分析分享一些解决方案。


对于甲骨文用户

解决方案 #1

您应该从 Tomcat 的 /lib 文件夹中删除 Oracle 驱动程序。我遇到了同样的问题,它得到了解决。

注意: 让 Oracle 驱动程序位于 /WEB-INF/lib 文件夹中。

解决方案#2

您可以通过休眠线程使用真正的 hack。

 @Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    logger.info("######### contextDestroyed #########");
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        try {
            DriverManager.deregisterDriver(driver);
            logger.info(String.format("deregistering jdbc driver: %s", driver));
        } catch (SQLException e) {
            logger.info(String.format("Error deregistering driver %s", driver), e);
        }
    }
    try { Thread.sleep(2000L); } catch (Exception e) {} // Use this thread sleep
}

资源链接: “Tomcat can’t stop [Abandoned connection cleanup thread]”的解决方案

解决方案#3

斯维特林·扎列夫 ( Svetlin Zarev ) 表示无需担心。这是tomcat的标准消息。他给出了如下根本原因分析:

当应用程序启动了 ScheduledExecutor(但任何其他 Thread/TheadPool 都会发生这种情况)并且没有在 contextDestroyed 上将其关闭时会发生此问题。因此,请检查您是否在应用程序/服务器停止时关闭线程。

资源链接: Tomcat8 内存泄漏

解决方案#4

对于 Oracle 用户,这篇文章中有多个答案: To prevent a memory leak, the JDBC Driver has been forcingly unregistered


对于 MySQL 用户

解决方案#5

根本原因分析及解决方案:

NonRegisteringDriver 类中废弃连接的清理线程被重构为具有静态关闭方法。内存已分配但从未释放。如果您遇到此泄漏问题,请使用 contextDestroyed 方法中的 AbandonedConnectionCleanupThread.shutdown() 调用在您的应用程序中实现上下文侦听器。

此问题在 Tomcat 应用程序服务器下运行的应用程序中发现,但它也可能适用于其他应用程序服务器。

例如:

 @WebListener
public class YourThreadsListener implements ServletContextListener {
   public void contextDestroyed(ServletContextEvent arg0) {
      try {
          AbandonedConnectionCleanupThread.shutdown();
      } catch (InterruptedException e) {
      }
   }
   ...
}

请注意,如果容器不支持注释,则将说明添加到 web.xml 中:

 <listener>
    <listener-class>user.package.YourThreadsListener</listener-class>
</listener>

资源链接: https ://docs.oracle.com/cd/E17952_01/connector-j-relnotes-en/news-5-1-23.html

原文由 SkyWalker 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题