簡體   English   中英

Web 應用程序似乎啟動了一個名為 [Timer-0] 的線程,但未能停止它

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

我正在使用 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)

為什么我會收到此錯誤,我該如何解決?

我想與此問題的根本原因分析分享一些解決方案。


對於 Oracle 用戶

解決方案#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 無法停止 [Abandoned connection cleanup thread]”的解決方法

解決方案#3

Svetlin Zarev沒有告訴任何人擔心。 這是tomcat的標准消息。 他給出了如下根本原因分析:

當應用程序已啟動 ScheduledExecutor(但這將與任何其他線程/TheadPool 一起發生)並且沒有在 contextDestroyed 上將其關閉時,會發生此問題。 因此,請檢查您是否在應用程序/服務器停止時關閉線程。

資源鏈接: Tomcat8 內存泄漏

解決方案#4

對於Oracle用戶,這個帖子有多個答案: 為了防止內存泄漏,JDBC Driver已被強制注銷


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

更改您的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);
    }
}

根據您的代碼運行一些測試並在線研究后,我的結論是:

  • 沒有什么可擔心的( 鏈接)。 Tomcat 進程正在完成,並且沒有留下任何內存泄漏。

  • 即使您調用AbandonedConnectionCleanupThread.shutdown()類的方法,您仍然可以獲得相同的警告( 鏈接

  • 調用startup.shshutdown.sh時會出現此警告。 從 Eclipse 運行 Tomcat 時,它不會顯示該警告。

  • 您的Executor的關閉方法可能會被調用。 對於我的測試,即使我沒有為執行程序定義destroyMethod ,它也會被調用。

  • 在這種情況下,此警告與任何 Spring 調度 bean 無關。 Executors.newScheduledThreadPool返回一個新的ScheduledThreadPoolExecutor ,它具有 destroy 方法並且它正在被銷毀,就像我之前指出的那樣。 您可以自己調試並查看。

  • 但是,在您的代碼中某處調用new java.util.Timer ,它調用new TimerThread() ,從您的日志中可以看出,正如@Claudio Corsi 所指出的那樣。

為了調試它,如果你使用的是 Eclipse ,你必須附上你的 JDK 版本的源代碼。 打開類聲明(按住 ctrl 並選擇打開聲明)並單擊“附加源代碼”按鈕。 確保您已下載完全相同的版本。 您甚至不必解壓縮 zip。 如果您使用的是 Maven,請稍等一下,它會自行下載。

然后,在java.util.Timer的構造函數中放置一個斷點並開始調試您的應用程序。

編輯:確定對java.util.Timer的引用后,將其保存(作為 bean,如果它不是一個)並在上下文銷毀時調用其cancel方法。

很難說根本原因,但線程名稱[Timer-0]提供了找到它的線索。 java.util.Timer類創建具有類似Timer-*的名稱模式的線程,如您在其源代碼中所見。

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

您的類路徑中的庫可能會啟動一個Timer線程,但不會取消它,或者在該線程中工作的代碼卡住了。

我可能會建議在java.util.Timer放置斷點並對其進行調試以查找哪些任務正在處理它。 它可能指出根本原因。

我也遇到了同樣的問題,出現以下錯誤:

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:

所以,過了一會兒,我發現我沒有為我的 spring-boot 應用程序中的所有子模塊進行 maven 安裝。 因此,請仔細檢查您是否遇到相同的錯誤:

  1. 您已經為項目中的所有子模塊以及項目本身運行了mvn clean install -U

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM