2012-10-15 13 views
8

Używam ThreadPoolExecutor do uruchamiania zadań. Backend to SynchronousQueue, więc jeśli executor jest już perfekcyjny, rzuca RejectedExecutionException. Oto prosty przypadek testowy:Czy moja pamięć wycieka z ThreadPoolExecutor?

public class ExecutorTest { 

    final static Worker worker = new Worker(); 

    public static void main(String[] args) { 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); 

    while (true) { 
     try {     
      executor.execute(worker);     
     }catch (RejectedExecutionException e) {     
     } 
    }   
    } 

    static class Worker implements Runnable { 

    private int i = 0; 
    private long start = System.currentTimeMillis(); 

    @Override 
    public void run() { 
     try { 
      Thread.sleep(1000); 
      System.out.println(++i + " " + (System.currentTimeMillis() - start)); 
     } catch (InterruptedException ex) {     
     } 
    } 
    } 
} 

Oczekiwany bahavious jest: Wykonanie pracownika i po spaniu na sekundę, wydrukować i (reprezentujący jak często pracownik został zrealizowany do tej pory), a ilość milisekund od pracownik został stworzony. Więc oczekuję:

1 1015 
2 2015 
3 3016 
4 4017 

Działa to dobrze na chwilę, ale po prawie na godzinę:

2919 2922196 
2920 2942951 
2921 2990407 

więc ilość czasu między jednym wykonaniu pracowników i następnego wynosi 20 sekund (2919-> 2920) i 38 sekund (2920-> 2921) i tak dalej. Wszystko staje się bardzo powolne, a jvm spędza dużo czasu na zbieraniu śmieci. W końcu (po kilku dniach) natrafiam na OutOfMemoryError.

Używam tego z opcją -Xmx8M (zakładam, że efekt pojawia się znacznie później z większą przestrzenią sterty) na JVM Oracle 1.7.0_07 na 64-bitowym komputerze z systemem Linux. Byłbym wdzięczny za wszelkie wskazówki, ale prawdopodobnie po prostu tęsknię za oczywistością.

+1

Może po upływie pewnego czasu sterty zapełniły się Wyrzuconymi Wyjątkami Wyjątkowymi (chociaż wydawało mi się, że obiekty wyjątków zostały ponownie użyte po pewnym czasie)? Czy próbowałeś profilować swoją aplikację? – assylias

+0

@assylias No cóż, profilowałem aplikację oczywiście, ale głupio spojrzałem tylko na przestrzeń sterty i gc, które przeżyły pokolenia. Używam teraz narzędzia do profilowania, aby sprawdzić, ale na pierwszy rzut oka wydaje się, że wyjątki RejctedExectutionException nie należą do sprawcy. Nawet jeśli tak, muszę złapać te wyjątki i na koniec dnia nie powinno zabraknąć pamięci, prawda? –

+0

To by wyjaśniało zwiększoną ilość GC, ale nie OOME ... – assylias

Odpowiedz

2

Możesz spróbować zmodyfikować instancję ThreadPoolExecutor. Trzeba tylko dodać argument do konstruktora, aby użyć RejectExecutionHandler, który po cichu odrzuci odrzucone zadania.

public static void main(String[] args) { 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy()); 

    while (true) { 
    executor.execute(worker);     
    } 
} 

Więc jeśli Twój problem wynika z wielokrotnym RejectedExecutionException (i myślę, że tak), można go uniknąć.

+1

+1 to znacznie zmniejsza ilość aktywności GC, jak pokazano przez "-verbose: gc -XX: + PrintGCDetails' – DNA

Powiązane problemy