2012-10-15 22 views
8

Görevleri çalıştırmak için ThreadPoolExecutor kullanıyorum. Arka uç bir SynchronousQueue, bu yüzden eğer yürütücü zaten bir görevi perfoming ediyorsa, RejectedExecutionException'u atar. İşte size basit bir test durumu var:ThreadPoolExecutor cihazım bellek sızdırıyor mu?

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

beklenen bahavious geçerli: işçi çalıştırır ve bir saniye uyuduktan sonra, çıktısını i (işçi şimdiye kadar yürütülmesinden ne sıklıkta temsil eden) ve o zamandan beri milisaniye miktarı işçi oluşturuldu. Yani bekliyorum:

1 1015 
2 2015 
3 3016 
4 4017 

Bu bir süre çalışıyor, ama neredeyse saatte sonra:

2919 2922196 
2920 2942951 
2921 2990407 

Yani bir işçi yürütme diğeri arasındaki süre 20 saniyedir (2919-> 2920) ve 38 saniye (2920-> 2921) ve benzerleri. Her şey aşırı derecede yavaşlar ve jvm çöp toplamada çok zaman harcıyor. Son olarak (birkaç gün sonra) bir OutOfMemoryError'a koşuyorum.

Bunu, 64bit Linux makinesinde Oracle'ın JVM 1.7.0_07'sinde -Xmx8M ile (daha fazla yığın alanıyla efektin çok daha geç bir şekilde göründüğünü varsayar) çalıştırıyorum. Herhangi bir işaretçi için minnettar olurum, ama muhtemelen sadece belli olanı özlüyorum.

+1

Belki bir süre sonra RejectedExecutionExceptions ile yığın yığılıyor (istisna objeleri bir süre sonra yeniden kullanılmasına rağmen düşündüm)? Uygulamanızı profillemeye çalıştınız mı? – assylias

+0

@assylias Eh, ben elbette uygulamayı profil, ama aptalca sadece yığın uzay ve gc nesiller kalan baktı. Hemen kontrol etmek için profilerle çalışıyorum ama ilk bakışta RejctedExectutionExceptions suçlu gibi görünmüyor. Olsa bile, bu istisnaları yakalamalıyım ve günün sonunda hafızam bitmemeliydiler, değil mi? –

+0

Bu, artan miktardaki GC'yi açıklar ama OOME ... – assylias

cevap

2

ThreadPoolExecutor örneğini değiştirmeyi deneyebilirsiniz. Sadece, reddedilen görevleri sessizce iptal edecek bir RejectExecutionHandler kullanmak için yapıcıya bir argüman eklemeniz gerekir.

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

Yani eğer senin sorunun (ve sanırım) tekrarlanan RejectedExecutionException geliyor, bunu önlemek olacaktır.

+1

+1, bu büyük ölçüde gb -XX: + PrintGCDetails' ile gösterildiği gibi GC etkinliğini azaltır. – DNA

İlgili konular