如何防止石英中的内存泄漏
我在我的项目中使用石英。 我的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.QuartzInitializerServlet
和org.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”。