2012-05-22 12 views
10

Używam kwarcu w moim projekcie. Moja aplikacja internetowa najwyraźniej spowodowała wyciek pamięci, kiedy się zatrzyma, błąd jest:Jak zapobiec wyciekowi pamięci w kwarcu?

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. 

użyłem org.quartz.ee.servlet.QuartzInitializerServlet i org.quartz.ee.servlet.QuartzInitializerListener. Kod dla mojej fabryki jest:

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

i ustawienia dla kwarcu w web.xml jest:

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

proszę mi pomóc rozwiązać ten przeciek pamięci !!

Odpowiedz

0

Myślę, że chcesz:

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

Masz „kwarc:” prefiks, które mogą być przyczyną Quartz, aby przywrócić domyślną wartość „false” dla tego ustawienia konfiguracji.

+0

Nie, prefiks "kwarc:" jest poprawny. odwiedź stronę: http: //quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerListener.html. –

+0

Czytasz niewłaściwą dokumentację: twój link jest do "Listenera" i konfigurujesz "Servlet". Z jakiegoś powodu nie zachowują się w ten sam sposób. Zobacz: http://quartz-scheduler.org/api/2.0.0/org/quartz/ee/servlet/QuartzInitializerServlet.html –

+0

to ustawienie dla org.quartz.ee.servlet.QuartzInitializerServlet i prefiksu "kwarc:" dla org.quartz.ee.servlet.QuartzInitializerListener. Jednak usunę prefiks "kwarcowy:", ale nie poprawny wyciek pamięci. –

2

widzę zainicjować dwie instancje ... - najpierw przez org.quartz.ee.servlet.QuartzInitializerServlet - sekundę przez org.quartz.ee.servlet.QuartzInitializerListener

Albo usunąć QuartzInitializerServlet lub QuartzInitializerListener (i również odpowiednich parametrów) ... Jeśli chcesz mieć wiele instancji (dla konkretnych powodów), iść z QuartzInitializerServlet (i nie zapomnij użyć inny na przykład)

4

poprzez wdrożenie org.quartz.InterruptableJob można prawidłowo przerwać wątki wywołane przez rozładowanie serwletów.

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

Ten przykład może spowodować błąd wyścigu o zmiennej wątku, jeśli zadanie nie zostało wykonane, zanim zostanie przerwany. Pozostawiam ostateczne rozwiązanie otwarte na sugestie, w zależności od cyklu życia docelowej aplikacji. Jeśli potrzebujesz równoczesnego wykonywania przez tę samą instancję zadania, rozszerz rozwiązanie, aby obsłużyć wiele wątków i usuń adnotację @DisallowConcurrentExecution.

Aby to zadziałało, właściwość kwarcu org.quartz.scheduler.interruptJobsOnShutdownWithWait musi być ustawiona na true. Można to zrobić, definiując plik właściwości dla programu planującego lub odwołanie do komponentów bean, jeśli używa się struktury sprężynowej.

Przykład quartz.properties file:

org.quartz.scheduler.interruptJobsOnShutdownWithWait=true 

Uwaga że przerwanie jest wywoływane tylko wtedy, gdy planista jest skonfigurowany tak, aby czekać na zamknięcie, co skutkuje wywołaniem scheduler.shutdown(true).

0

Jeśli używasz własnej implementacji interfejsu ServletContextListener dla swojej aplikacji internetowej, możesz zamknąć kwarc z wdziękiem w metodzie contextestrasse. Poniżej znajduje się przykładowy kod wersji Quartz 2.1.7.

Twoje zadanie:

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

Twój harmonogram pracy:

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

} 

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

} 

Twojej web.xml

<listener> 
    <listener-class>my.package.name.MyServletContextListener</listener-class> 
</listener> 
Powiązane problemy