2009-06-16 3 views
15

finalize 호출 중에 현재 객체에 대한 참조를 저장하면 어떻게됩니까? 예 :finalize 중 객체 참조

class foo { 
    ... 
    public void finalize() { 
     bar.REFERENCE = this; 
    } 
} 

개체가 가비지 수집 되었습니까? 아니요? 나중에 bar.REFERENCE에 액세스하려고하면 어떻게됩니까?

+4

+1 왜냐하면 좋은 질문이기는하지만 이것은 단지 지적 운동 이었기를 바랍니다. ;) –

+0

걱정하지 마십시오. –

답변

11

개체가 가비지 수집되지 않습니다. 이것은 "개체 부활"로 알려져 있습니다.

당신이 조심해야, 종료 자이 GC가 .NET과 같은 몇 가지 enviroments에에, 다시 전화하지 않을 것이다라고하면 당신은 종료자를 다시 등록 할 수 있습니다하지만 난 자바에 대한 확실하지 않다

6

이런 종류의 것은 finalize()의 사용이 일반적으로 권장되지 않는 이유입니다.

+0

Finalize는 관리되지 않는 리소스에 대한 참조를 해제하는 데에만 사용해야합니다. GC는 결국 모든 관리 참조를 처리합니다. –

+6

아니요, 나중에 임의로 실행되거나 전혀 실행되지 않으므로 finalize를 사용해서는 안됩니다. 관리되지 않는 리소스는 finally 블록에서 명시 적으로 해제해야합니다.기껏해야 finalize()가 추가 된 failsafe가 될 수 있습니다. –

+1

...하지만 안전 장치로도 매우 문제가 있습니다. 비 결정적이기 때문에 재현 가능한 리소스 누출이 간헐적 인 리소스 누출로 바뀌며 이는 자주 발생하지는 않지만 재현하기가 훨씬 어렵습니다. 그곳에 갔다 :-(. – sleske

1

인스턴스에서 finalize() 메서드를 명시 적으로 호출하거나 해당 개체가 사용하는 저장소를 다시 사용할 때 가비지 수집기에서 호출 할 수 있습니다.

bar이 유효한 인스턴스 인 경우 REFERENCE 필드를 foo 인스턴스로 설정합니다. 가비지 컬렉터의 관점에서 이것은 foo의 참조 카운트를 증가시킵니다. 예외가 finalize()있어서 내부 발생되면

(예는 예를 들어 NullPointerExceptionbar 때문에 null 임), 다음 마무리 프로세스는 단순히 종료한다.

N.B. 다른 사람들이 지적했듯이 당신의 모범은 분명히 피해야 할 대상입니다.

9

절대적으로 개체를 부활시켜야하는 경우이 JavaWorld 문서에서는 마무리되는 인스턴스를 다시 부활시키는 것이 아니라 새로운 인스턴스를 만드는 것이 좋습니다. 왜냐하면 마무리되는 인스턴스가 다시 수집 할 자격이 생기면 다시 수집되기 때문입니다 (종료자가 실행되지 않기 때문입니다 다시).

0

Java는 안전한 언어 및 플랫폼이므로 메모리는 해제되지 않습니다. 또한 연결된 PhantomReferenceReferenceQueue에 대기열에 포함되지 않습니다. VM은 한 번 객체에 finalize 만 호출합니다. JVM Spec에는 멋진 상태 다이어그램이 있습니다.

일반적으로 finalizer를 사용하는 경우 API를 방해하지 않도록 선언문을 @Override protected void finalize() throws Throwable으로 남겨 두어야합니다. 심지어 Effective Java 1st Ed 에서처럼 보호 된 finalizer를 사용하십시오.

Princeton의 한 그룹이 신뢰할 수없는 코드에서 사용자 정의 ClassLoader을 만들 때이 특별한 트릭이 헤드 라인 (San Jose Mercury의 어쨌든)을 강타했습니다. 스펙이 다소 조여졌지만 (finalizer가 호출되기 전에 Object 생성자가 정상적으로 실행을 끝내야 만합니다 (Java SE 6에서 구현 된 J2SE 5.0에서 지정됨), 여전히 문제 영역으로 남아 있습니다. API를 디자인하는 경우 민감한 클래스는 하위 클래스가 될 수 없으므로 많은 슬픔을 피하십시오.