如何防止石英中的内存泄漏

我在我的项目中使用石英。 我的Web应用程序显然在停止时导致内存泄漏,错误是:

SEVERE: A web application appears to have started a TimerThread named [Timer-12] via the java.util.Timer API but has failed to stop it. To prevent a memory leak, the timer (and hence the associated thread) has been forcibly cancelled. Jan 2, 2013 6:55:35 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads SEVERE: A web application appears to have started a thread named [DefaultQuartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak. 

我使用了org.quartz.ee.servlet.QuartzInitializerServletorg.quartz.ee.servlet.QuartzInitializerListener 。 我工厂的代码是:

 StdSchedulerFactory factory = (StdSchedulerFactory) context.getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY ); 

和web.xml中的quartz设置是:

   QuartzInitializer   Quartz Initializer Servlet   org.quartz.ee.servlet.QuartzInitializerServlet   1   shutdown-on-unload true   wait-on-shutdown true   start-scheduler-on-load true    quartz:shutdown-on-unload true   quartz:wait-on-shutdown true   quartz:start-on-load true    org.quartz.ee.servlet.QuartzInitializerListener   

请帮我解决这个内存泄漏!!

通过实现org.quartz.InterruptableJob您可以正确地中断由servlet卸载触发的线程。

 @DisallowConcurrentExecution public class Job implements InterruptableJob { private Thread thread; @Override public void execute(JobExecutionContext context) throws JobExecutionException { thread = Thread.currentThread(); // ... do work } @Override public void interrupt() throws UnableToInterruptJobException { thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { throw new UnableToInterruptJobException(e); } finally { // ... do cleanup } } } 

如果作业在中断之前尚未执行,则此示例可能会导致线程变量出现争用条件错误。 我将最终解决方案打开以获取建议,具体取决于目标应用程序的生命周期。 如果需要通过同一个作业实例进行并发执行,请扩充解决方案以处理多个线程并删除@DisallowConcurrentExecution批注。

为了使其工作,必须将quartz属性org.quartz.scheduler.interruptJobsOnShutdownWithWait设置为true 。 这可以通过为调度程序定义属性文件来完成,或者如果使用spring框架则通过bean引用来完成。

示例quartz.properties文件:

 org.quartz.scheduler.interruptJobsOnShutdownWithWait=true 

请注意 ,如果调度程序配置为在关闭时等待,则仅调度中断,从而调用scheduler.shutdown(true)

我看到你初始化了两个实例…… – 首先通过org.quartz.ee.servlet.QuartzInitializerServlet – 第二个通过org.quartz.ee.servlet.QuartzInitializerListener

删除QuartzInitializerServlet或QuartzInitializerListener(以及相应的参数)…如果你想拥有多个实例(由于特定的原因),请使用QuartzInitializerServlet(并且不要忘记使用不同的每个实例)

如果您正在为Web应用程序使用自己的ServletContextListener接口实现,则可以在contextDestroyed方法中正常关闭Quartz。 请在下面找到Quartz版本2.1.7的示例代码。

你的工作:

 import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class CronJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { // TODO: do you job } } 

你的工作安排:

 import org.quartz.CronScheduleBuilder; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; public class CronJobScheduler { private static CronJobScheduler instance = new CronJobScheduler(); private Scheduler scheduler; private CronJobScheduler() { try { scheduler = new StdSchedulerFactory().getScheduler(); } catch (SchedulerException e) { // TODO } } public static CronJobScheduler getInstance() { return instance; } public void trigger() { JobKey jobKey = JobKey.jobKey("myJobName", "myJobGroup"); JobDetail job = JobBuilder.newJob(CronJob.class).withIdentity(jobKey).build(); Trigger trigger = TriggerBuilder .newTrigger() .withIdentity("myTriggerName", "myJobGroup") .withSchedule(CronScheduleBuilder.cronSchedule("0 0 1,13 * * ?")) .build(); try { scheduler.start(); scheduler.scheduleJob(job, trigger); } catch (SchedulerException e) { // TODO } } public void shutdown(boolean waitForJobsToComplete) { try { scheduler.shutdown(waitForJobsToComplete); } catch (SchedulerException e) { // TODO } } } 

您的ServletContextListener接口的实现:

 import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent arg0) { CronJobScheduler.getInstance().shutdown(true); } @Override public void contextInitialized(ServletContextEvent arg0) { CronJobScheduler.getInstance().trigger(); } } 

你的web.xml

  my.package.name.MyServletContextListener  

我想你想要:

   wait-on-shutdown true  

您有一个“quartz:”前缀,可能导致Quartz恢复为该配置设置的默认值“false”。