Java Thread Garbage được thu thập hay không


85

Câu hỏi này đã được đăng trên một số trang web. Tôi không tìm thấy câu trả lời đúng ở đó, vì vậy tôi đăng lại ở đây.

public class TestThread {
    public static void main(String[] s) {
        // anonymous class extends Thread
        Thread t = new Thread() {
            public void run() {
                // infinite loop
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    // as long as this line printed out, you know it is alive.
                    System.out.println("thread is running...");
                }
            }
        };
        t.start(); // Line A
        t = null; // Line B
        // no more references for Thread t
        // another infinite loop
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            System.gc();
            System.out.println("Executed System.gc()");
        } // The program will run forever until you use ^C to stop it
    }
}

Truy vấn của tôi không phải về việc dừng một Chủ đề. Hãy để tôi nói lại câu hỏi của tôi. Dòng A (xem đoạn mã ở trên) bắt đầu một Chủ đề mới; và Dòng B làm cho tham chiếu luồng trống. Vì vậy, JVM bây giờ có một Đối tượng Chủ đề (đang ở trạng thái đang chạy) mà không có tham chiếu nào tồn tại (như t = null trong Dòng B). Vì vậy, câu hỏi của tôi là, tại sao luồng này (không còn tham chiếu trong luồng chính) tiếp tục chạy cho đến khi luồng chính đang chạy. Theo hiểu biết của tôi, đối tượng luồng lẽ ra đã được thu gom rác sau Dòng B. Tôi đã cố gắng chạy đoạn mã này trong 5 phút và hơn, yêu cầu Java Runtime chạy GC, nhưng luồng không dừng lại.

Hy vọng cả mã và câu hỏi đều rõ ràng lần này.

Câu trả lời:


123

Một luồng đang chạy được coi là một gốc thu gom rác và là một trong những thứ đó giữ cho mọi thứ không bị thu gom rác. Khi trình thu gom rác xác định liệu đối tượng của bạn có ' có thể truy cập được ' hay không, nó luôn làm như vậy bằng cách sử dụng tập hợp gốc của trình thu gom rác làm điểm tham chiếu.

Hãy xem xét điều này, tại sao luồng chính của bạn không được thu gom rác, không ai tham chiếu đến luồng đó.


16
Câu trả lời này, như hiện tại, đặt ra câu hỏi liệu các chủ đề có thể được GC'ed hay không (sau khi chúng kết thúc). Vì câu hỏi này được đánh dấu là trùng lặp với câu hỏi này , nên cần lưu ý rằng các luồng sẽ không còn được đánh dấu là "gốc thu gom rác" sau khi chúng kết thúc và do đó, chúng có thể truy cập được đối với GC.
bluenote 10

13
Câu cuối mới thấm thía: "main thread của bạn tại sao không phải là rác ...".
Yếu tố quyết định

vì vậy như một phần tiếp theo, một chuỗi đã xử lý (một chuỗi đã được tham gia) sẽ không còn được coi là gốc? Tôi gần như chắc chắn câu trả lời là có, nhưng tôi nhìn thấy những điều kỳ lạ về ứng dụng của tôi dưới profiler và nó đã cho tôi tự hỏi ...
Groostav

1
Tôi càng đọc nhiều câu trả lời, tôi càng bối rối, nhưng vâng tại sao chủ đề chính không được thu gom rác là điều cần suy ngẫm. Nhưng quay lại câu hỏi cốt lõi, nếu các luồng con tạo ra một số đối tượng thì nó sẽ không nhận được GCed vì luồng mẹ vẫn đang chạy và giữ các tham chiếu của các luồng con ngay cả khi chúng đã 'hết' (!! ??)
Rahul Kumar

@Groostav Một luồng đã được tham gia không chạy, vì vậy nó không phải là gốc thu gom rác. Nhưng khi luồng cha được gọi child.join(), nó có một tham chiếu đến child. Nếu tham chiếu đó (và bất kỳ tham chiếu nào khác) không bị hủy, chuỗi con không thể được GCed.
Blaisorblade

23

Như đã được giải thích, các luồng đang chạy, theo định nghĩa, miễn nhiễm với GC. GC bắt đầu công việc của mình bằng cách quét các "gốc", được coi là luôn có thể truy cập được; root bao gồm các biến toàn cục ("trường tĩnh" trong Java-talk) và ngăn xếp của tất cả các luồng đang chạy (có thể hình dung rằng ngăn xếp của một luồng đang chạy tham chiếu đến Threadcá thể tương ứng ).

Tuy nhiên, bạn có thể tạo một luồng thành một luồng "daemon" (xem Thread.setDaemon(boolean)). Một luồng daemon không được thu gom rác nhiều hơn một luồng không phải là daemon, nhưng JVM sẽ thoát khi tất cả các luồng đang chạy là daemon. Một cách để hình dung là mọi luồng, khi nó kết thúc, sẽ kiểm tra xem có còn một số luồng không phải daemon đang chạy hay không; nếu không, luồng kết thúc buộc một System.exit()cuộc gọi sẽ thoát khỏi JVM (giết các luồng daemon đang chạy). Đây không phải là vấn đề liên quan đến GC; theo một cách nào đó, các chủ đề được phân bổ theo cách thủ công. Tuy nhiên, đây là cách JVM có thể chịu đựng các luồng bán giả mạo. Điều này thường được sử dụng cho các Timertrường hợp.


19

JVM có tham chiếu đến tất cả các luồng đang chạy.

Không có luồng nào (hoặc những thứ mà nó đề cập đến) sẽ được thu gom rác trong khi nó vẫn đang chạy.


13

Chủ đề không được thu thập rác vì có các tham chiếu đến các chủ đề mà bạn không thể nhìn thấy. Ví dụ, có các tham chiếu trong hệ thống thời gian chạy.

Khi Luồng được tạo, nó sẽ được thêm vào nhóm luồng hiện tại. Bạn có thể nhận danh sách các Chủ đề trong nhóm luồng hiện tại, vì vậy đó là một cách khác để tham chiếu đến nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.