我正在使用ThreadPoolExecutor
來運行任務。後端是SynchronousQueue
,所以如果執行程序已經執行任務,則會拋出RejectedExecutionException
。這裏有一個簡單的測試案例:我的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) {
}
}
}
}
預期bahavious是:執行的工人,睡了一秒鐘後,打印出我(代表多久工人迄今已執行)和毫秒的,因爲量工人被創建。 所以我很期待:
1 1015
2 2015
3 3016
4 4017
這一段時間工作正常,但幾乎小時後:
2919 2922196
2920 2942951
2921 2990407
所以一個工人執行和下一個之間的時間量爲20秒(2919-> 2920)和38秒(2920-> 2921)等等。一切都變得非常緩慢,jvm花費大量時間進行垃圾收集。最後(幾天之後),我遇到了OutOfMemoryError。
我在64位Linux機器上的Oracle JVM 1.7.0_07上使用-Xmx8M(我假設效果出現得更晚,堆空間更多)運行此操作。我會很欣賞任何指針,但可能我只是想念明顯。
也許堆會在一段時間後變得擁擠與RejectedExecutionExceptions(儘管我認爲異常對象被重用一段時間後)?你有沒有試圖分析你的應用程序? – assylias
@assylias當然,我描繪了應用程序,但愚蠢地只看堆空間和gc倖存的一代。我現在正在運行分析器來檢查,但乍一看,RejctedExectutionException似乎不是罪魁禍首。即使它們是,我必須趕上這些例外情況,並且不應該在一天結束時耗盡內存,對吧? –
這將解釋增加的GC數量,但不是OOME ...... – assylias