简体   繁体   English

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

[英]The web application appears to have started a thread named [Timer-0] but has failed to stop it

I am using Spring Boot 1.5.9.RELEASE + Java 8 + Tomcat 9 + Jersey + Oracle and my app has scheduled method defined as follows:我正在使用 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);
    }
}

The job class:工作类别:

@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);
        }
    }

}

Also I have a class to deregister the Oracle driver as follows:我还有一个类来取消注册 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);
            }

        }
    }

}

but when stopping Tomcat I am getting the following error:但是在停止 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)

Why am I getting this error and how can I fix it?为什么我会收到此错误,我该如何解决?

I want to share some solutions with root cause analysis of this issue.我想与此问题的根本原因分析分享一些解决方案。


For Oracle Users对于 Oracle 用户

Solution #1解决方案#1

You should remove your Oracle driver from Tomcat's /lib folder.您应该从 Tomcat 的/lib文件夹中删除您的 Oracle 驱动程序。 I was facing the same issue and it got resolved.我遇到了同样的问题,它得到了解决。

Note: Let the Oracle driver be in /WEB-INF/lib folder.注意:让 Oracle 驱动程序位于/WEB-INF/lib文件夹中。

Solution #2解决方案#2

You can use real hack by sleeping thread.您可以通过休眠线程使用真正的 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
}

Resource Link: Solution to “Tomcat can't stop [Abandoned connection cleanup thread]”资源链接: “Tomcat 无法停止 [Abandoned connection cleanup thread]”的解决方法

Solution #3解决方案#3

Svetlin Zarev has told nothing to worry about. Svetlin Zarev没有告诉任何人担心。 It is the standard message of tomcat.这是tomcat的标准消息。 He has given root cause analysis like below:他给出了如下根本原因分析:

This problem is occurred when an application has started ScheduledExecutor (but this will happen with any other Thread/TheadPool) and didn't shut it down on contextDestroyed.当应用程序已启动 ScheduledExecutor(但这将与任何其他线程/TheadPool 一起发生)并且没有在 contextDestroyed 上将其关闭时,会发生此问题。 So check if you are shutting down your threads on application/server stop.因此,请检查您是否在应用程序/服务器停止时关闭线程。

Resource Link: Tomcat8 memory leak资源链接: Tomcat8 内存泄漏

Solution #4解决方案#4

For Oracle users , there are multiple answers in this post: To prevent a memory leak, the JDBC Driver has been forcibly unregistered对于Oracle用户,这个帖子有多个答案: 为了防止内存泄漏,JDBC Driver已被强制注销


For MySQL users对于 MySQL 用户

Solution #5解决方案#5

Root Cause Analysis with Solution:解决方案的根本原因分析:

The cleanup thread for abandoned connections in the NonRegisteringDriver class was refactored to have a static shutdown method. NonRegisteringDriver类中废弃连接的清理线程被重构为具有静态关闭方法。 Memory was allocated but never released.内存已分配但从未释放。 If you encountered this leak problem, implement the context listener in your application with the AbandonedConnectionCleanupThread.shutdown() call in the contextDestroyed method.如果您遇到此泄漏问题,请使用contextDestroyed方法中的AbandonedConnectionCleanupThread.shutdown()调用在您的应用程序中实现上下文侦听器。

This issue was found in applications running under the Tomcat application server, but it might have also applied to other application servers.在 Tomcat 应用程序服务器下运行的应用程序中发现了此问题,但它可能也适用于其他应用程序服务器。

For example:例如:

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

Note that if container does not support annotations, you add the description to web.xml:请注意,如果容器不支持注释,则将描述添加到 web.xml:

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

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

Change your ScheduleConfig to use shutdownNow instead of shutdown as destroy method.更改您的ScheduleConfig以使用shutdownNow而不是shutdown作为销毁方法。

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

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

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

My conclusions after running a few tests based on your code and researching online:根据您的代码运行一些测试并在线研究后,我的结论是:

  • There's nothing to worry about ( link ).没有什么可担心的( 链接)。 Tomcat process is being finished and there's no memory leaks left behind. Tomcat 进程正在完成,并且没有留下任何内存泄漏。

  • Even if you call something like AbandonedConnectionCleanupThread.shutdown() , you could still get that same Warning ( link )即使您调用AbandonedConnectionCleanupThread.shutdown()类的方法,您仍然可以获得相同的警告( 链接

  • This warning happens when calling startup.sh and shutdown.sh .调用startup.shshutdown.sh时会出现此警告。 When running Tomcat from Eclipse, it doesn't show that Warning.从 Eclipse 运行 Tomcat 时,它不会显示该警告。

  • Your shutdown method for the Executor is likely being called.您的Executor的关闭方法可能会被调用。 For my tests, it was getting called even if I didn't define the destroyMethod for the executor.对于我的测试,即使我没有为执行程序定义destroyMethod ,它也会被调用。

  • In this case, this warning is not related to any Spring Scheduling bean.在这种情况下,此警告与任何 Spring 调度 bean 无关。 Executors.newScheduledThreadPool returns a new ScheduledThreadPoolExecutor , which has the destroy method and it is getting destroyed, like I pointed out earlier. Executors.newScheduledThreadPool返回一个新的ScheduledThreadPoolExecutor ,它具有 destroy 方法并且它正在被销毁,就像我之前指出的那样。 You can debug and see it for yourself.您可以自己调试并查看。

  • However, there's somewhere at your code calling new java.util.Timer , which calls new TimerThread() , ass seen from your logging, and as pointed out by @Claudio Corsi.但是,在您的代码中某处调用new java.util.Timer ,它调用new TimerThread() ,从您的日志中可以看出,正如@Claudio Corsi 所指出的那样。

In order to debug it and if you are using Eclipse , you have to attache the source code for your JDK version.为了调试它,如果你使用的是 Eclipse ,你必须附上你的 JDK 版本的源代码。 Open the class declaration (hold ctrl and choose open declaration) and click the "Attach Source Code" button.打开类声明(按住 ctrl 并选择打开声明)并单击“附加源代码”按钮。 Make sure you have dowloaded the exact same version.确保您已下载完全相同的版本。 You don't even have to extract the zip.您甚至不必解压缩 zip。 If you're using Maven, just hold on a bit that it will download for itself.如果您使用的是 Maven,请稍等一下,它会自行下载。

Then, place a breakpoint in the constructor for java.util.Timer and start debugging your application.然后,在java.util.Timer的构造函数中放置一个断点并开始调试您的应用程序。

Edit : After identifying a reference to java.util.Timer , save it (as a bean, if it's not one) and call its cancel method on context destroy.编辑:确定对java.util.Timer的引用后,将其保存(作为 bean,如果它不是一个)并在上下文销毁时调用其cancel方法。

It is hard to say root cause but thread name [Timer-0] gives a clue to find it.很难说根本原因,但线程名称[Timer-0]提供了找到它的线索。 java.util.Timer class creates threads which has name pattern like Timer-* as you can see in it's source code. java.util.Timer类创建具有类似Timer-*的名称模式的线程,如您在其源代码中所见。

public Timer() {
    this("Timer-" + serialNumber());
}

Possibly the libraries that are in your classpath starts a Timer thread but doesn't cancel it or the code which is working in this thread stuck.您的类路径中的库可能会启动一个Timer线程,但不会取消它,或者在该线程中工作的代码卡住了。

I may suggest put breakpoint in java.util.Timer and debug it to find which tasks is working on it.我可能会建议在java.util.Timer放置断点并对其进行调试以查找哪些任务正在处理它。 It may point the root cause.它可能指出根本原因。

I have also got the same issue with following error:我也遇到了同样的问题,出现以下错误:

The web application [ROOT] appears to have started a thread named [cluster-ClusterId{value='5d29b78967e4ce07d9bb8705', description='null'}-localhost:27017] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:

So, after a while I figured it out that I didn't do the maven install for all sub modules in my spring-boot application.所以,过了一会儿,我发现我没有为我的 spring-boot 应用程序中的所有子模块进行 maven 安装。 So, double check if you are having same error that:因此,请仔细检查您是否遇到相同的错误:

  1. You have run mvn clean install -U for all sub modules in the project and for the project itself too.您已经为项目中的所有子模块以及项目本身运行了mvn clean install -U

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 该Web应用程序似乎已启动一个名为的线程,但未能停止该线程。 这很可能造成内存泄漏 - The web application appears to have started a thread named but has failed to stop it. This is very likely to create a memory leak Web应用程序[VehicleRouting]似乎已启动名为[drools-worker-4]的线程,但未能停止它 - The web application [VehicleRouting] appears to have started a thread named [drools-worker-4] but has failed to stop it Quartz2.x:严重:Web应用程序[/ servlet]似乎已启动名为[Thread-4]的线程,但未能停止它 - Quartz2.x: GRAVE: The web application [/servlet] appears to have started a thread named [Thread-4] but has failed to stop it Web应用程序似乎已启动名为[22]的线程但未能阻止它。 这很可能造成内存泄漏 - A web application appears to have started a thread named [22] but has failed to stop it. This is very likely to create a memory leak 如何解决 tomcat 内存泄漏警告 - Web 应用程序已启动一个线程但未能将其停止 - How to resolve tomcat memory leak warning - The web application have started a thread but has failed to stop it 启动了一个名为MultiThreadedHttpConnectionManager清理的线程,但未能将其停止 - Started a thread named MultiThreadedHttpConnectionManager cleanup but has failed to stop it 运行应用程序时引发线程“ Timer-0”中的异常 - Exception in thread “Timer-0” thrown when run the application Tomcat webapp错误-应用程序启动了线程[AWT-Windows],但未能将其停止-内存泄漏? - Tomcat webapp error - application started thread [AWT-Windows] but has failed to stop it - memory leak? Servlet“已启动一个线程但未能阻止它” - Tomcat中的内存泄漏 - Servlet “has started a thread but failed to stop it” - memory leak in Tomcat 线程“ Timer-0” java.lang.NoClassDefFoundError中的异常: - Exception in thread “Timer-0” java.lang.NoClassDefFoundError:
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM