我正在使用 springboot 1.5.9.RELEASE + Java 8 + tomcat 9 + 泽西 + Oracle ,我的应用程序的计划方法定义如下:
.vtt
工作班:
@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);
}
}
我还有一个类来取消注册oracle驱动程序,如下所示:
@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);
}
}
}
但是当停止tomcat时我收到以下错误:
@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);
}
}
}
}
请告知我为什么会收到此错误以及如何解决此问题,谢谢。
答案 0 :(得分:5)
将您的 bacardi breezer aldi rum white coconut
bacardi 0 2 0 1 0 0
breezer 2 0 0 0 0 0
aldi 0 0 0 1 1 0
rum 1 0 1 0 1 1
white 0 0 1 1 0 0
coconut 0 0 0 1 0 0
drinks 0 0 0 1 0 1
daniel 0 0 0 1 0 0
改为使用ScheduleConfig
而不是shutdownNow
作为销毁方法。
shutdown
答案 1 :(得分:4)
我想与这个问题的根本原因分析分享一些解决方案。
对于Oracle用户:
<强>溶液#1:强>
您可以从/WEB-INF/lib
文件夹中删除Oracle驱动程序,并将其放在Tomcat的/lib
文件夹中。它可以解决您的问题。
<强>溶液#2:强>
你可以通过睡眠线程使用真正的黑客。
@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
}
资源链接: Solution to “Tomcat can’t stop [Abandoned connection cleanup thread]”
<强>解决方案#3:强>
Svetlin Zarev没有任何担心。这是tomcat的标准消息。他已经给出了如下的根本原因分析:
应用程序启动时发生此问题 ScheduledExecutor(但这将与任何其他人一起发生 Thread / TheadPool)并没有在contextDestroyed上关闭它。所以 检查您是否在应用程序/服务器上关闭线程 停止。
资源链接: Tomcat8 memory leak
<强>溶液#4:强>
对于Oracle用户,此帖子中有多个答案:To prevent a memory leak, the JDBC Driver has been forcibly unregistered
<强>解决方案#5:强>
解决方案的根本原因分析:
中放弃连接的清理线程 NonRegisteringDriver 类被重构为具有静态关闭方法。内存已分配,但从未发布。如果你 遇到这个泄漏问题,在你的实现上下文监听器 应用
AbandonedConnectionCleanupThread.shutdown()
使用contextDestroyed
方法调用。在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
答案 2 :(得分:2)
根据您的代码运行一些测试后的结论 和在线研究:
没有什么可担心的(link)。 Tomcat进程正在完成,并且没有留下内存泄漏。
即使您拨打AbandonedConnectionCleanupThread.shutdown()
之类的内容,
你仍然可以得到相同的警告(link)
调用startup.sh
和shutdown.sh
时会出现此警告。
从Eclipse运行Tomcat时,它没有显示Warning。
可能会调用Executor
的关闭方法。
对于我的测试,即使我没有定义destroyMethod
,它也会被调用
执行人。
在这种情况下,此警告与任何Spring Scheduling bean无关。
Executors.newScheduledThreadPool
返回新的ScheduledThreadPoolExecutor
,
它有破坏方法,它正在被破坏,就像我之前指出的那样。您可以自己调试和查看。
但是,您的代码呼叫new java.util.Timer
的某个地方,
调用new TimerThread()
,
从你的伐木中看到的,正如@Claudio Corsi所指出的那样。
为了调试它并且如果您使用的是Eclipse , 你必须附上JDK版本的源代码。 打开类声明(按住ctrl并选择打开声明) 并单击&#34;附加源代码&#34;按钮。确保你已经下载了 完全相同的版本。你甚至不必提取拉链。 如果你正在使用Maven,只需稍等一下即可自行下载。
然后,在java.util.Timer
的构造函数中放置一个断点
并开始调试您的应用程序。
修改:在确定对java.util.Timer
的引用后,将其保存(如果它不是一个bean),并在上下文中调用其cancel
方法破坏。
答案 3 :(得分:1)
很难说根本原因但是线程名称 [Timer-0] 提供了找到它的线索。 java.util.Timer
类创建的线程具有名称模式,如 Timer - * ,如您在其源代码中所见。
public Timer() {
this("Timer-" + serialNumber());
}
您的类路径中的库可能会启动 Timer 线程,但不会取消它或者此线程中的代码卡住了。
我可能会建议在java.util.Timer
中放置断点并调试它以查找正在处理它的任务。它可能指出了根本原因。
答案 4 :(得分:0)
我也遇到相同的问题,但出现以下错误:
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安装。因此,请仔细检查您是否遇到以下错误:
mvn clean install -U
。