2012-03-29 25 views
5

My Tomcat 7 được báo cáo rằng có thể có một rò rỉ bộ nhớ trong webapp của tôiJava webapp rò rỉ bộ nhớ khi sử dụng ScheduledExecutorService

SEVERE: The web application [/mywebapp] appears to have started a 
thread named [pool-1-thread-1] but has failed to stop it. This is 
very likely to create a memory leak. 

Tôi có một nhiệm vụ chạy dài trong webapp của tôi mà được khởi tạo khi webapp được bắt đầu.

public class MyContextListener implements ServletContextListener{ 
Scheduler scheduler = null; 

public MyContextListener(){ 
    scheduler = new Scheduler(); 
} 

@Override 
public void contextDestroyed(ServletContextEvent arg0) { 
    scheduler.stop(); 
} 

@Override 
public void contextInitialized(ServletContextEvent arg0) { 
    scheduler.start(); 
} 

} 

.. và Scheduler.java tôi

public class Scheduler { 
private final ScheduledExecutorService fScheduler; 

public Scheduler() { 
    fScheduler = Executors.newScheduledThreadPool(1); 
} 


public void start(){ 
    fScheduler.scheduleWithFixedDelay(new Runnable() { 

     @Override 
     public void run() { 
      //Perform some task 
     } 
    }, 1, 240, TimeUnit.MINUTES); 
} 

public void stop(){ 
    fScheduler.shutdownNow(); 
} 

}

Mặc dù tôi gọi scheduler.stop(); khi tắt máy chủ, nó vẫn báo cáo có thể có một rò rỉ bộ nhớ.

Ứng dụng này được triển khai trên jelastic.com và tôi thấy rằng khi ứng dụng được bắt đầu, nó chạy tốt trong khoảng hai ngày và sau đó các tác vụ dường như không chạy. Cũng không có ngoại lệ hoặc lỗi trong nhật ký.

Tôi có làm gì sai ở đây không? Có thực sự là một rò rỉ bộ nhớ tiềm năng?

Trả lời

6

Calling fScheduler.shutdownNow(); là không đủ:

Có gì đảm bảo ngoài nhất nỗ lực cố gắng để ngăn chặn xử lý tích cực thực hiện nhiệm vụ.

Từ JavaDoc.

Thay vào đó bạn phải chờ đợi một cách rõ ràng cho các nhiệm vụ hiện đang chạy:

fScheduler.shutdownNow(); 
fScheduler.awaitTermination(10, TimeUnit.SECONDS); 
+0

hmm .. Tôi nghĩ có thể trong một số trường hợp hiếm hoi. Nhiệm vụ của tôi chạy mỗi 240 phút và không mất quá vài phút để hoàn thành. không phải là chạy, không nên nó có thể tắt máy đúng cách? Câu trả lời của bạn có lẽ là đúng nhưng tôi chỉ tò mò :) – Krishnaraj

+0

@Krishnaraj Bạn có chắc chắn rằng nhiệm vụ của bạn đang chấm dứt nhanh như bạn nghĩ? Bạn có thể muốn đăng nhập khi nhiệm vụ của bạn bắt đầu/dừng lại để xác minh nó không bị chặn. –

+0

@ increment1 Có, nhiệm vụ của tôi hoàn thành trong không quá 5 phút. – Krishnaraj

1

Tôi tin rằng bạn không nên gọi tắt từ Listener nhưng từ Servlet trực tiếp.

contextDestroyed() của người nghe đã quá muộn cho dịch vụ thi hành. Như đã nêu trong javadoc Tất cả các servlet và bộ lọc sẽ bị hủytrướcbất kỳ ServletContextListeners nào được thông báo về sự phá hủy ngữ cảnh.

trong khi trọng các servlet destroy() nên được OK như theo javadoc Phương pháp này cung cấp cho các servlet một cơ hội để làm sạch bất kỳ tài nguyên đang được tổ chức (ví dụ, bộ nhớ, xử lý tập tin,đề ..

@Override 
public void destroy() { 


    fScheduler.shutdownNow(); 
    fScheduler.awaitTermination(10, TimeUnit.SECONDS); 

    super.destroy(); 
} 
+0

Sử dụng Servlet.destroy() là một ý tưởng rất tồi. Container miễn phí để dỡ bỏ Servlet khỏi bộ nhớ (gọi hàm destroy() trong quá trình) bất cứ khi nào nó thích. –

+0

@MarkThomas Cũng tồn tại 'Servlet' Javadoc * Sau khi servlet container gọi phương thức này, nó sẽ không gọi lại phương thức dịch vụ trên servlet này. *. Nói cách khác, servlet sẽ không bao giờ được sử dụng nữa. Tôi không thể thấy vấn đề của bạn là gì. Nếu bạn liên kết một tài nguyên với servlet này (Thread, file handle, ...) khi 'destroy()' được gọi, servlet chỉ là, hủy diệt dứt khoát, và bất kỳ tài nguyên ràng buộc nào cũng sẽ bị hủy. –

+0

Bạn cần đọc thông số kỹ thuật Servlet, đặc biệt là sesion trên vòng đời của servlet. Phương thức init() được gọi một lần khi cá thể được tạo ra (một cá thể được tạo để xử lý tất cả các yêu cầu). Phương thức service() được gọi một lần theo yêu cầu. Ví dụ tương tự có thể xử lý nhiều yêu cầu đồng thời. Phương thức destroy() được gọi khi instance được unloaded có thể ở bất kỳ thời điểm nào (nếu một request khác được nhận cho servlet sau khi cá thể đã bị phá hủy instance mới sẽ được tạo). Tất cả điều này đều bỏ qua mô hình luồng đơn được phản chiếu. –