Java Thread Garbage 수집 여부


85

이 질문은 일부 사이트에 게시되었습니다. 거기에서 정답을 찾지 못해서 다시 여기에 게시하겠습니다.

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

내 질문은 스레드 중지에 관한 것이 아닙니다. 내 질문을 다시 말하겠습니다. 라인 A (위의 코드 참조)는 새 스레드를 시작합니다. 라인 B는 스레드 참조를 null로 만듭니다. 따라서 JVM에는 이제 참조가없는 스레드 개체 (실행 중 상태)가 있습니다 (줄 B의 t = null). 그래서 내 질문은 왜이 스레드 (주 스레드에 더 이상 참조가 없음)가 주 스레드가 실행될 때까지 계속 실행됩니까? 내 이해에 따르면 스레드 개체는 라인 B 이후에 가비지 수집되어야합니다.이 코드를 5 분 이상 실행하여 Java 런타임에 GC를 실행하도록 요청했지만 스레드가 멈추지 않습니다.

이번에는 코드와 질문이 모두 명확하기를 바랍니다.

답변:


124

실행중인 스레드는 소위 가비지 콜렉션 루트로 간주되며 가비지 콜렉션되지 않도록하는 것 중 하나입니다. 가비지 수집기가 개체가 ' 도달 할 수 있는지'여부를 결정할 때 항상 가비지 수집기 루트 집합을 참조 지점으로 사용합니다.

이것을 고려하십시오. 왜 메인 스레드가 가비지 수집되지 않고 아무도 그 스레드를 참조하지 않습니다.


17
이 대답은 현재로서는 스레드가 종료 된 후 전혀 GC 될 수 있는지에 대한 질문을 제기합니다. 이 질문의 중복으로 표시되어 있기 때문에 이 하나 , 그들이 종료 후 스레드가 더 이상 "가비지 컬렉션 뿌리"로 표시됩니다, 따라서, 그들은 GC에 대한 도달하게 언급 될 수 없습니다.
bluenote10

13
마지막 문장은 "왜 당신의 메인 스레드가 쓰레기가되지 않는가 ..."입니다.
결정자

후속 조치로 폐기 된 스레드 (결합 된 스레드)가 더 이상 루트로 간주되지 않습니까? 대답이 예라고 거의 확신합니다.하지만 프로파일 러 아래에서 내 응용 프로그램에서 이상한 일을보고 궁금해합니다.
Groostav

1
내가 더 많은 답변을 읽을수록 더 혼란스러워 지지만, 예를 들어 메인 스레드가 가비지 수집을받지 않는 이유는 고민해야 할 사항입니다. 그러나 핵심 질문으로 돌아와서 자식 스레드가 일부 객체를 생성하면 부모 스레드가 여전히 실행 중이기 때문에 GCed를 얻지 못하며 '실행'(!! ??)하더라도 자식 스레드의 참조를 보유합니다.
Rahul Kumar

@Groostav 조인 된 스레드가 실행 중이 아니므로 가비지 컬렉션 루트가 아닙니다. 부모 스레드라고하지만 child.join(), 그것은에 대한 참조를했다 child. 해당 참조 (및 다른 참조)가 삭제되지 않으면 자식 스레드를 GC 할 수 없습니다.
Blaisorblade 2017 년

23

설명했듯이 실행중인 스레드는 정의에 따라 GC에 영향을받지 않습니다. GC는 항상 도달 가능한 것으로 간주되는 "루트"를 스캔하여 작업을 시작합니다. 루트는 전역 변수 (Java-talk의 "정적 필드")와 실행중인 모든 스레드의 스택 (실행중인 스레드의 스택이 해당 Thread인스턴스를 참조한다고 상상할 수 있음 )을 포함합니다.

그러나 스레드를 "데몬"스레드로 만들 수 있습니다 (참조 Thread.setDaemon(boolean)). 데몬 스레드는 데몬이 아닌 스레드보다 더 이상 가비지 수집되지 않지만 실행중인 모든 스레드가 데몬이면 JVM이 종료됩니다. 이를 상상하는 한 가지 방법은 모든 스레드가 종료 될 때 데몬이 아닌 실행 스레드가 남아 있는지 확인하는 것입니다. 그렇지 않은 경우 종료 스레드 System.exit()는 JVM을 종료 하는 호출을 강제 실행합니다 (실행중인 데몬 스레드 종료). 이것은 GC 관련 문제가 아닙니다. 어떤 방식으로 스레드는 수동으로 할당됩니다. 그러나 이것이 JVM이 세미 로그 스레드를 허용하는 방법입니다. 일반적으로 Timer인스턴스에 사용됩니다 .


19

JVM에는 실행중인 모든 스레드에 대한 참조가 있습니다.

스레드 (또는 참조하는 것)는 실행중인 동안 가비지 수집되지 않습니다.


13

스레드는 볼 수없는 스레드에 대한 참조가 있기 때문에 가비지 수집되지 않습니다. 예를 들어 런타임 시스템에는 참조가 있습니다.

스레드가 생성되면 현재 스레드 그룹에 추가됩니다. 현재 스레드 그룹의 스레드 목록을 가져올 수 있으므로 참조를 얻는 또 다른 방법입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.