2010-03-12 3 views
25

자바에서 가비지 컬렉션에 대한 질문이 this topic입니다. 그러나 내가 얻은 대답은 또 다른 질문을했습니다.클래스가 Java에서 언제 가비지 수집됩니까?

누군가 가비지 컬렉터도 클래스를 수집 할 수 있다고 언급했습니다. 사실입니까?

그리고 이것이 사실이라면 어떻게 작동합니까?

+3

이 주제가 도움이 될 것입니다 : http://stackoverflow.com/questions/453023/are-static-fields-open-for-garbage-collection –

+1

"Java 클래스 로더가 언제 어떻게 표시됩니까?" 쓰레기 수거를 위해? " http://stackoverflow.com/questions/2344964/when-and-how-is-a-java-classloader-marked-for-garbage-collection – ewernli

답변

29

Java의 클래스는 아무 것도 참조하지 않을 때 가비지 수집 될 수 있습니다. 대부분의 간단한 설정에서는 이러한 일이 발생하지 않지만 상황이 발생할 수 있습니다. 그 클래스의

  • 객체는 여전히 연결할 수 :

    는 클래스에 도달하고, 따라서 GC 대상이되지 않도록하는 방법에는 여러 가지가 있습니다. 클래스를 나타내는

  • Class 객체는 클래스가 여전히 연결할 수로드 ClassLoaderClassLoader에 의해로드
  • 다른 클래스가 여전히 연결할 수
  • 아직 도달

것도 그 중 사실이 없을 경우 , ClassLoader 및로드 된 모든 클래스는 GC에 적합합니다.

는 여기에 건설 예제 동작을 설명한다 그 (나쁜 관행이 가득!) : (포장하지!) x

이 디렉토리에 바이트 코드 파일 GCTester.class을 작성합니다. 그것은의 소스 코드는 다음과 같습니다

 
in main 
Creating ClassLoader 
Loading Class 
Getting static field 
Reading static value 
[email protected] created 
Got value: [email protected] 
First gc() call 
Second gc() call (in main) 
[email protected] finalized 
End of main 

에서 :

import java.io.File; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.lang.reflect.Field; 

public class TestMe { 
    public static void main(String[] args) throws Exception { 
    System.out.println("in main"); 
    testGetObject(); 
    System.out.println("Second gc() call (in main)"); 
    System.gc(); 
    Thread.sleep(1000); 
    System.out.println("End of main"); 
    } 

    public static void testGetObject() throws Exception { 
    System.out.println("Creating ClassLoader"); 
    ClassLoader cl = new URLClassLoader(new URL[] {new File("./x").toURI().toURL()}); 
    System.out.println("Loading Class"); 
    Class<?> clazz = cl.loadClass("GCTester"); 

    System.out.println("Getting static field"); 
    Field field = clazz.getField("INSTANCE"); 

    System.out.println("Reading static value"); 
    Object object = field.get(null); 
    System.out.println("Got value: " + object); 

    System.out.println("First gc() call"); 
    System.gc(); 
    Thread.sleep(1000); 
    } 
} 

이 (또는 유사한) 출력을 생성 TestMe 실행 :

public class GCTester { 
    public static final GCTester INSTANCE=new GCTester(); 

    private GCTester() { 
    System.out.println(this + " created"); 
    } 

    public void finalize() { 
    System.out.println(this + " finalized"); 
    } 
} 

그런 다음 x의 상위 디렉토리에서 클래스 TestMe을 만들 두 번째 줄부터 마지막 ​​줄까지 GCTester 인스턴스가 완료됨을 알 수 있습니다. 이는 클래스 (및 ClassLoader)는 가비지 수집 대상입니다.

+9

@ Joachim Sauer : * finalize() *가 호출된다는 사실 만이 입증됩니다. 이 경우 개체가 "도달 할 수없는"상태로 이동하고 GCed가 아닌 것입니다. GC는 의지에 따라 자유롭게 수집 할 수 있습니다. 즉, finalize가 호출되었다고해서 해당 객체가 GCed되었음을 의미하지는 않습니다. GCed되었는지 추적하고 싶다면 PhantomReference를 ReferenceQueue에 놓고 그 큐에서 폴링해야합니다. 그리고 어쨌든, 객체가 실제로 GCed되었음을 증명할지라도, 이것은 클래스와 클래스 로더 (예제에서) 만 GC에 적합하고 자동으로 GCed되지는 않습니다. – SyntaxT3rr0r

+0

@Wizard : 사실, "GC에 적합하다"고 말했어 야합니다. –

+0

@ JoachimSauer, 당신은 'Class'가 GC에 적합하지 못하게하는 4 가지 조건 (4 점)을 명시했습니다. 이제 4 가지 장애물을 해결 했더라도 시스템이 '클래스'를 수집하지 못할 가능성이 있습니까? 기본적으로 JLS는 JVM *이 참조되지 않은'Class'를 릴리즈해야한다고 말하고 있습니까? 아니면 JVM *이 ** 반드시 ** 참조되지 않은'Class'를 릴리스해야한다고 말하는 것입니까? – Pacerier

관련 문제