2012-05-22 15 views
10

Estoy usando cuarzo en mi proyecto. Mi aplicación web aparentemente ha causado una pérdida de memoria cuando se detiene, el error es:Cómo prevenir una fuga de memoria en cuarzo

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. 

que utiliza org.quartz.ee.servlet.QuartzInitializerServlet y org.quartz.ee.servlet.QuartzInitializerListener. El código para mi fábrica es:

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

y la configuración de cuarzo en web.xml es:

<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> 

me puede ayudar a resolver este pérdida de memoria !!

Respuesta

0

Creo que desee:

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

Usted tiene una "cuarzo:" prefijo que puede ser la causa de cuarzo para volver al valor por defecto de "falsa" para ese parámetro de configuración.

+0

no, el prefijo "quartz:" es correcto. por favor visite: http: //quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerListener.html. –

+0

Está leyendo la documentación incorrecta: su enlace es al "Oyente" y está configurando el "Servlet". Por alguna razón, no se comportan de la misma manera. Consulte: http://quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerServlet.html –

+0

esta configuración es para org.quartz.ee.servlet.QuartzInitializerServlet y el prefijo "quartz:" es para org.quartz.ee.servlet.QuartzInitializerListener. Sin embargo, borro el prefijo "quartz:" pero no corrijo la pérdida de memoria. –

2

veo inicializar dos casos ... - primero a través de org.quartz.ee.servlet.QuartzInitializerServlet - segundo través org.quartz.ee.servlet.QuartzInitializerListener

quite QuartzInitializerServlet o QuartzInitializerListener (y también correspondientes parámetros) ... Si usted quiere tener varias instancias (por razones específicas), ir con la QuartzInitializerServlet (y no se olvide de utilizar diferentes por ejemplo)

4

mediante la implementación de org.quartz.InterruptableJob puede interrumpir adecuadamente las discusiones provocadas por descarga de 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 
     } 
    } 
} 

Este ejemplo puede causar un error de condición de carrera en la variable de hilo, si el trabajo no se ha ejecutado antes de que se interrumpe. Dejo la solución final abierta para sugerencias, dependiendo del ciclo de vida de la aplicación de destino. Si necesita una ejecución simultánea a través de la misma instancia de trabajo, aumente la solución para manejar varios subprocesos y elimine la anotación @DisallowConcurrentExecution.

Para que esto funcione, la propiedad de cuarzo org.quartz.scheduler.interruptJobsOnShutdownWithWait debe establecerse en true. Esto se puede hacer definiendo un archivo de propiedades para el programador, o mediante referencias de un bean si se usa un marco de primavera.

Ejemplo quartz.properties archivo:

org.quartz.scheduler.interruptJobsOnShutdownWithWait=true 

Nota que la interrupción solamente se distribuye si el programador está configurado para esperar en la parada, lo que resulta en una llamada a scheduler.shutdown(true).

0

Si está utilizando su propia implementación de la interfaz ServletContextListener para su aplicación web, puede apagar Quartz correctamente en el método contextDestroyed. A continuación, encontrará el código de muestra para Quartz versión 2.1.7.

Su trabajo:

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 
    } 
} 

Su planificador de tareas:

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 
     } 
    } 

} 

Su implementación de la interfaz 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(); 
    } 

} 

Su Web.xml

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