2012-05-22 86 views
10

我在我的項目中使用石英。我的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是:

<servlet> 
     <servlet-name> 
      QuartzInitializer 
     </servlet-name> 
     <display-name> 
      Quartz Initializer Servlet 
     </display-name> 
     <servlet-class> 
      org.quartz.ee.servlet.QuartzInitializerServlet 
     </servlet-class> 
     <load-on-startup> 
      1 
     </load-on-startup> 
     <init-param> 
      <param-name>shutdown-on-unload</param-name> 
      <param-value>true</param-value> 
     </init-param> 
     <init-param> 
      <param-name>wait-on-shutdown</param-name> 
      <param-value>true</param-value> 
     </init-param> 
     <init-param> 
      <param-name>start-scheduler-on-load</param-name> 
      <param-value>true</param-value> 
     </init-param> 
    </servlet> 
    <context-param> 
     <param-name>quartz:shutdown-on-unload</param-name> 
     <param-value>true</param-value> 
    </context-param> 
    <context-param> 
     <param-name>quartz:wait-on-shutdown</param-name> 
     <param-value>true</param-value> 
    </context-param> 
    <context-param> 
     <param-name>quartz:start-on-load</param-name> 
     <param-value>true</param-value> 
    </context-param> 
    <listener> 
     <listener-class> 
      org.quartz.ee.servlet.QuartzInitializerListener 
     </listener-class> 
    </listener> 

請幫我解決這個內存泄漏!

回答

0

我想你想:

 <init-param> 
     <param-name>wait-on-shutdown</param-name> 
     <param-value>true</param-value> 
    </init-param> 

你有一個「石英:」前綴可能會導致石英恢復到「假」爲配置設置的默認值。

+0

不,「quartz:」前綴是正確的。請訪問:http://quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerListener.html。 –

+0

您正在閱讀錯誤的文檔:您的鏈接是「Listener」,您正在配置「Servlet」。出於某種原因,他們的表現並不一樣。請參閱:http://quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerServlet.html –

+0

此設置適用於org.quartz.ee.servlet.QuartzInitializerServlet和「quartz:」前綴爲for org.quartz.ee.servlet.QuartzInitializerListener。但是,我刪除了「quartz:」前綴但不正確的內存泄漏。 –

2

我看你初始化兩個實例... - 首先通過org.quartz.ee.servlet.QuartzInitializerServlet - 第二通過org.quartz.ee.servlet.QuartzInitializerListener

要麼刪除QuartzInitializerServlet或QuartzInitializerListener(和也相應參數)... 如果你想有(具體原因)的多個實例,與QuartzInitializerServlet去(不要忘記使用每個實例不同)

4

通過實施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 
     } 
    } 
} 

這個例子可能對線程變量的競爭條件錯誤,如果它被中斷前的工作還沒有被執行。我根據目標應用程序的生命週期,提供最終解決方案以獲得建議。如果您需要通過同一個作業實例進行併發執行,請增加解決方案以處理多個線程並刪除註釋。

爲了達到此目的,必須將石英屬性org.quartz.scheduler.interruptJobsOnShutdownWithWait設置爲true。這可以通過定義調度程序的屬性文件來完成,或者通過使用spring框架的bean引用來完成。

quartz.properties文件:

org.quartz.scheduler.interruptJobsOnShutdownWithWait=true 

注意,如果調度被配置爲等待關機,造成scheduler.shutdown(true)通話中斷只出動。

0

如果您正在爲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 CronJobTrigger 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

<listener> 
    <listener-class>my.package.name.MyServletContextListener</listener-class> 
</listener>