2012-10-15 24 views
8

Tôi đang sử dụng ThreadPoolExecutor để chạy các tác vụ. Phần phụ trợ là SynchronousQueue, vì vậy nếu người thực hiện đã hoàn thành một nhiệm vụ, nó sẽ ném RejectedExecutionException. Dưới đây là một trường hợp thử nghiệm đơn giản:Bộ nhớ rò rỉ ThreadPoolExecutor của tôi có bị hỏng không?

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

Các bahavious dự kiến ​​là: Thực hiện các công nhân và sau khi ngủ trong một giây, in ra i (đại diện cho mức độ thường xuyên người lao động đã được thực hiện cho đến nay) và số lượng mili giây kể từ khi nhân viên đã được tạo. Vì vậy, tôi mong đợi:

1 1015 
2 2015 
3 3016 
4 4017 

này hoạt động tốt trong một thời gian, nhưng sau gần trên giờ:

2919 2922196 
2920 2942951 
2921 2990407 

Vì vậy, khoảng thời gian giữa một thi nhân và người tiếp theo là 20 giây (2919-> 2920) và 38 giây (2920-> 2921) và vv. Mọi thứ trở nên cực kỳ chậm và jvm dành nhiều thời gian trong việc thu gom rác thải. Cuối cùng (sau một vài ngày) tôi chạy vào một OutOfMemoryError.

Tôi đang chạy ứng dụng này với -Xmx8M (Tôi cho rằng hiệu ứng xuất hiện sau này với nhiều khoảng trống hơn) trên JVM 1.7.0_07 của Oracle trên máy Linux 64 bit. Tôi đánh giá cao bất kỳ con trỏ, nhưng có lẽ tôi chỉ thiếu rõ ràng.

+1

Có thể vùng heap bị tụt hậu với RejectedExecutionExceptions sau một thời gian (mặc dù tôi nghĩ các đối tượng ngoại lệ đã được sử dụng lại sau một thời gian)? Bạn đã cố gắng để hồ sơ ứng dụng của bạn? – assylias

+0

@assylias Vâng, tôi đã lược tả các ứng dụng tất nhiên, nhưng ngu ngốc chỉ nhìn vào không gian heap và gc thế hệ còn sống sót. Tôi đang chạy profiler ngay bây giờ để kiểm tra, nhưng ngay từ cái nhìn đầu tiên RejctedExectutionExceptions dường như không phải là thủ phạm. Ngay cả khi họ đang có, tôi phải nắm bắt những ngoại lệ và không nên hết bộ nhớ vào cuối ngày, phải không? –

+0

Điều đó sẽ giải thích số lượng GC tăng lên nhưng không phải là số ... – assylias

Trả lời

2

Bạn có thể thử sửa đổi số phát hành ThreadPoolExecutor. Bạn chỉ cần thêm đối số vào hàm tạo để sử dụng RejectExecutionHandler sẽ tự động loại bỏ các tác vụ bị từ chối.

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

Vì vậy nếu vấn đề của bạn xuất phát từ lặp đi lặp lại RejectedExecutionException (và tôi nghĩ như vậy), bạn sẽ tránh nó.

+1

+1 điều này làm giảm đáng kể số lượng hoạt động GC như được hiển thị bởi '-verbose: gc -XX: + PrintGCDetails' – DNA

Các vấn đề liên quan