当前位置: 首页 > 知识库问答 >
问题:

Tomcat中的Quartz调度程序内存泄漏

龙凯
2023-03-14

我使用石英版2.2.2和Spring Boot版1.3.1。它表现正常,一切正常。但是当我试图关闭这个应用程序时,问题出现了。日志显示有内存泄漏...

我的石英配置;

org.quartz.scheduler.instanceName = my-app-jobs
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.threadCount=2
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.scheduler.skipUpdateCheck = true

我有两个班,执行如下工作;

/**
 *
 * To Run Every 15 Minutes
 *
 */
public class MemoryDataUpdateJob implements Job {

    @Autowired
    private Dao dao;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Logger.info(getClass().getName(), "Scheduled Memory Data Update Job Started...");

        //Read Device Settings
        dao.readDeviceSettings();

        Logger.info(getClass().getName(), "Scheduled Memory Data Update Job Finished.");
    }

}

另一个班也同样做着不同的事情。

调度器工厂Bean如下;

@Bean
public SchedulerFactoryBean schedulerFactoryBean(
        JobFactory jobFactory,
        @Qualifier("MemoryDataUpdateJobTrigger") Trigger memoryDataUpdateJobTrigger,
        @Qualifier("MsgCountJobTrigger") Trigger msgCountJobTrigger) throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
    factory.setJobFactory(jobFactory);
    factory.setQuartzProperties(quartzProperties());
    factory.setTriggers(memoryDataUpdateJobTrigger, msgCountJobTrigger);
    return factory;
}

我得到了像下面这样的tomcat日志;

19-Jan-2016 11:18:39.722 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [MyApp-1.0.0] appears to have started a thread named [schedulerFactoryBean_Worker-1] 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)

19-Jan-2016 11:18:39.722 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [MyApp-1.0.0] appears to have started a thread named [schedulerFactoryBean_Worker-2] 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)

查阅了quartz文档,并在properties中添加了以下内容:;

org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownhook.cleanShutdown = true

第一条线程消息消失了,但关于worker-2的第二条消息仍然存在。

但在我的应用程序记录器中,我看到了这样的内容;

[2016-01-19 11:18:39:681] [DEBUG] [schedulerFactoryBean_Worker-1] [org.quartz.simpl.SimpleThreadPool:612] - WorkerThread is shut down.

[2016-01-19 11:18:40:047] [DEBUG] [schedulerFactoryBean_Worker-2] [org.quartz.simpl.SimpleThreadPool:612] - WorkerThread is shut down.

[2016-01-19 11:18:40:049] [INFO ] [Quartz Shutdown-Hook schedulerFactoryBean] [org.quartz.plugins.management.ShutdownHookPlugin:126] - Shutting down Quartz...

问题是什么?为什么即使应用程序记录器显示线程已关闭,也会出现内存泄漏?

共有2个答案

劳灵均
2023-03-14

至少从Spring 3.0开始,SchedulerFactoryBean就有一个标志来告诉它等待作业完成。设置标志并确保在关闭时调用销毁方法:

@Bean(destroyMethodName="destroy")
public SchedulerFactoryBean schedulerFactoryBean(
        JobFactory jobFactory,
        @Qualifier("MemoryDataUpdateJobTrigger") Trigger memoryDataUpdateJobTrigger,
        @Qualifier("MsgCountJobTrigger") Trigger msgCountJobTrigger) throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
    factory.setWaitForJobsToCompleteOnShutdown(true);
    factory.setJobFactory(jobFactory);
    factory.setQuartzProperties(quartzProperties());
    factory.setTriggers(memoryDataUpdateJobTrigger, msgCountJobTrigger);
    return factory;
}

或使用XML配置:

<bean id="scheduler"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
        destroy-method="destroy">
    <property name="waitForJobsToCompleteOnShutdown" value="true" />
    ....
</bean>

请参阅:https://docs.spring.io/spring-framework/docs/3.0.0.RELEASE/javadoc-api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html#setWaitForJobsToCompleteOnShutdown(布尔)

锺离嘉容
2023-03-14

知道了。问题是tomcat正在关闭,但quartz作业正在运行。如果我们等待一秒钟,它就会正常关闭。我们可以通过扩展SchedulerFactoryBean并重写它的destroy方法来实现。如下所示;

public class SchedulerFactoryBeanWithWait extends SchedulerFactoryBean {

@Override
public void destroy() throws SchedulerException {
    super.destroy();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        logError(e);
    }
 }
}

bean声明;

@Bean
public SchedulerFactoryBeanWithWait schedulerFactoryBeanWithWait (
        JobFactory jobFactory,
        @Qualifier("MemoryDataUpdateJobTrigger") Trigger memoryDataUpdateJobTrigger,
        @Qualifier("MsgCountJobTrigger") Trigger msgCountJobTrigger) throws IOException {
    SchedulerFactoryBeanWithWait factory = new SchedulerFactoryBeanWithWait ();
    factory.setJobFactory(jobFactory);
    factory.setQuartzProperties(quartzProperties());
    factory.setTriggers(memoryDataUpdateJobTrigger, msgCountJobTrigger);
    return factory;
}

这使得它等待线程关闭。也许这对将来的人有帮助。

 类似资料:
  • 当我们试图取消部署应用程序时,一些Oracle类似乎正在泄漏。在使用旧的OJDBC14.jar驱动程序时,我没有看到这种情况,但我们不能使用这些驱动程序,因为我们正在迁移到Oracle11g,这需要更新的驱动程序。我猜这是Oracle驱动程序中的bug?我能做些什么来清理这些资源吗?我尝试关闭数据库连接池和其他东西,但没有成功... 我不使用Tomcat的连接池会更好吗?我们宁愿让服务器连接到数据

  • 我使用Quartz Scheduler(使用JobDetailFactoryBean)和Spring来安排一些作业。现在我通过XmlApplicationContext通过spring配置实现了这一点,我必须将其更改为AnnotationConfigApplicationContext。那么,我如何在AnnotationConfigApplicationContext中实现这个cronjob呢。这

  • 我使用spring scheduler运行使用cron计时器的方法,如下所示。应用程序至少有50个与下面用粗体表示的类相同的调度器bean。我们通过在属性部分中给出的xml传递配置参数来创建新bean。但是我们从Tomcat6.0.36中得到一个错误,如下所示为斜体文本。这是一个问题吗?有什么方法可以克服这个错误。如果我们像下面给出的那样添加了很多计划任务,这不会影响应用程序的性能吗? 严重:we

  • 问题内容: 由于Tomcat中的孤立线程,我遇到了内存泄漏。特别是,Guice和JDBC驱动程序似乎没有关闭线程。 我知道这与其他问题,但是就我而言,“不必担心”的答案是不够的,因为它给我带来了麻烦。我的CI服务器会定期更新此应用程序,重新加载6-10次后,由于Tomcat内存不足,CI服务器将挂起。 我需要能够清理这些孤立的线程,以便可以更可靠地运行CI服务器。任何帮助,将不胜感激! 问题答案:

  • 我在log4j v1中面临内存泄漏的问题。如何解决这个内存泄漏问题。此方法是定期检查log4j.properties文件在我的类中的更新。 PropertyConfigutaror.ConfigureandWatch(time_ms); 但是在关机期间,tomcat内存泄漏问题就来了。日志如下: 提前致谢

  • 我的应用程序出现OutOfMemory异常。我已经把垃圾堆和垫子翻了个底朝天。在分析我的应用程序内存使用情况时,我发现以下疑点。我无法理解这些嫌疑人背后的主要原因。 请帮助我了解这种泄漏的怀疑和什么相关的解决方案。 “AJP-Bio-9002”-exec-5 at java.util.arrays.copyof([ci)[C(arrays.java:2882)at java.lang.abstra