2008-09-20 7 views
26

(Câu hỏi kiểu nguy hiểm, tôi muốn câu trả lời đã trực tuyến khi tôi gặp sự cố này)Tại sao chương trình Java của tôi bị rò rỉ bộ nhớ khi tôi gọi run() trên một đối tượng Thread?

Sử dụng Java 1.4, tôi có phương pháp mà tôi muốn chạy làm chủ đề một thời gian, nhưng không phải lúc khác . Vì vậy, tôi đã khai báo nó như là một lớp con của Thread, sau đó được gọi là start() hoặc run() tùy thuộc vào những gì tôi cần.

Nhưng tôi thấy rằng chương trình của tôi sẽ bị rò rỉ bộ nhớ theo thời gian. Tôi đang làm gì sai?

Trả lời

45

Đây là một lỗi được biết đến trong Java 1.4: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087

Nó cố định trong Java 1.5 nhưng Sun không có ý định để sửa chữa nó trong 1.4.

Vấn đề là, tại thời điểm xây dựng, Thread được thêm vào danh sách tham chiếu trong bảng chủ đề nội bộ. Nó sẽ không bị xóa khỏi danh sách đó cho đến khi phương thức start() của nó hoàn tất. Miễn là tài liệu tham khảo đó ở đó, nó sẽ không bị thu gom rác.

Vì vậy, đừng bao giờ tạo chuỗi trừ khi bạn chắc chắn sẽ gọi phương thức start() của nó. Không được gọi trực tiếp phương thức run() của đối tượng Thread của đối tượng.

Cách tốt hơn để viết mã là triển khai giao diện Runnable thay vì phân lớp Thread. Khi bạn không cần một sợi, gọi

myRunnable.run(); 

Khi bạn cần một sợi:

Thread myThread = new Thread(myRunnable); 
myThread.start(); 
+0

Đây có phải là sự cố phụ thuộc vào triển khai thực hiện (ví dụ JVM của Sun) hay được nêu ở đâu đó trong Đặc tả Ngôn ngữ Java không? – Alexander

+0

Đã chỉnh sửa - Tôi đã thực hiện một số điều tra khác và đó là lỗi JVM – slim

2

Hãy xem liệu chúng ta có thể nhận được gần hơn với cốt lõi của vấn đề:

Nếu bạn bắt đầu chương trình của bạn (cho phép nói) 1000 x bằng cách sử dụng start(), sau đó 1000 x bằng cách sử dụng run() trong một chủ đề, làm cả hai bộ nhớ lỏng lẻo? Nếu vậy, thuật toán của bạn nên được kiểm tra (tức là đối với các đối tượng bên ngoài như Vectors được sử dụng trong Runnable của bạn).

Nếu không có rò rỉ bộ nhớ như được mô tả ở trên thì bạn nên điều tra về bắt đầu tham số và sử dụng bộ nhớ của các chủ đề liên quan đến JVM.

3

Tôi nghi ngờ rằng việc xây dựng một thể hiện của một Chủ đề hoặc một lớp con sẽ làm rò rỉ bộ nhớ. Thứ nhất, không có gì trong các loại được đề cập trong Javadocs hoặc Đặc tả Ngôn ngữ Java. Thứ hai, tôi chạy một thử nghiệm đơn giản và nó cũng cho thấy rằng không có ký ức đang bị rò rỉ (ít nhất là không phải trên của Sun JDK 1.5.0_05 trên 32-bit x86 Linux 2.6):

public final class Test { 
    public static final void main(String[] params) throws Exception { 
    final Runtime rt = Runtime.getRuntime(); 
    long i = 0; 
    while(true) { 
     new MyThread().run(); 
     i++; 
     if ((i % 100) == 0) { 
     System.out.println((i/100) + ": " + (rt.freeMemory()/1024/1024) + " " + (rt.totalMemory()/1024/1024)); 
     } 
    } 
    } 

    static class MyThread extends Thread { 
    private final byte[] tmp = new byte[10 * 1024 * 1024]; 

    public void run() { 
     System.out.print("."); 
    } 
    } 
} 

EDIT: Chỉ cần tóm tắt ý tưởng thử nghiệm ở trên. Mỗi cá thể của lớp con MyThread của một Thread tham chiếu mảng 10 MB của riêng nó. Nếu các phiên bản MyThread không được thu thập rác, JVM sẽ hết bộ nhớ khá nhanh. Tuy nhiên, việc chạy mã thử nghiệm cho thấy JVM đang sử dụng một lượng bộ nhớ không đổi nhỏ bất chấp số lượng MyThread được xây dựng cho đến nay. Tôi tuyên bố điều này là bởi vì các trường hợp của MyThread được thu gom rác.

+3

Aha - đã thực hiện một số nghiên cứu khác và phát hiện ra rằng đó là lỗi đã được khắc phục trong Java 1.5 – slim