Cómo prevenir una pérdida de memoria en cuarzo

Estoy usando cuarzo en mi proyecto. Aparentemente, mi aplicación web ha causado una pérdida de memoria cuando se detiene, el error es:

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.

solía org.quartz.ee.servlet.QuartzInitializerServlet y org.quartz.ee.servlet.QuartzInitializerListener. El código de 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>

por favor ayúdenme a resolver esta pérdida de memoria!!

preguntado el 22 de mayo de 12 a las 15:05

4 Respuestas

Implementando org.quartz.InterruptableJob puede interrumpir adecuadamente los subprocesos activados por la descarga del 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 subproceso, si el trabajo no se ha ejecutado antes de que se interrumpa. Dejo la solución final abierta a sugerencias, según el 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 el @DisallowConcurrentExecution anotación.

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

Ejemplo quartz.properties archivo:

org.quartz.scheduler.interruptJobsOnShutdownWithWait=true

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

respondido 07 mar '13, 11:03

Veo que inicializa dos instancias... - primero a través de org.quartz.ee.servlet.QuartzInitializerServlet - segundo a través de org.quartz.ee.servlet.QuartzInitializerListener

Quite QuartzInitializerServlet o QuartzInitializerListener (y también los parámetros correspondientes)... Si desea tener múltiples instancias (por razones específicas), vaya con QuartzInitializerServlet (y no olvide usar diferentes por instancia)

Respondido el 24 de Septiembre de 12 a las 12:09

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

Tu 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 programador de trabajos:

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

}

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();
    }

}

Tu web.xml

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

Respondido 17 Abr '18, 07:04

Tuve una implementación y un problema similares. La verdad en el método shutdown() funcionó para mí: Felipe Guajardo

Creo que quieres:

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

Tiene un prefijo "quartz:" que puede estar causando que Quartz vuelva al valor predeterminado de "falso" para esa configuración.

contestado el 22 de mayo de 12 a las 16:05

ningún prefijo ، "quartz:" es correcto. por favor visita:cuarzo-programador.org/api/2.0.0/org/quartz/ee/servlet/… . - Alí Farozi

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. Ver: cuarzo-programador.org/api/2.0.0/org/quartz/ee/servlet/… - cristobal schultz

esta configuración es para org.quartz.ee.servlet.QuartzInitializerServlet y el prefijo "quartz:" es para org.quartz.ee.servlet.QuartzInitializerListener. Sin embargo, elimino el prefijo "quartz:" pero no corrijo la fuga de memoria. - Alí Farozi

Iría y preguntaría a la gente de Quartz, entonces, si no escuchan nada sobre este tema en SE por un tiempo. - cristobal schultz

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.