[java] Java에 대한 소멸자가 있습니까?

Java에 대한 소멸자가 있습니까? 이것에 대한 문서를 찾을 수없는 것 같습니다. 그렇지 않은 경우 어떻게 동일한 효과를 얻을 수 있습니까?

내 질문을보다 구체적으로 만들기 위해 데이터를 다루는 응용 프로그램을 작성 중이며 사양에 따라 응용 프로그램을 원래 시작된 상태로 되돌릴 수있는 ‘재설정’버튼이 있어야한다고 말합니다. 그러나 응용 프로그램을 닫거나 재설정 버튼을 누르지 않으면 모든 데이터가 ‘실시간’이어야합니다.

일반적으로 C / C ++ 프로그래머이기 때문에 구현하기가 쉽지 않을 것이라고 생각했습니다. (따라서 마지막으로 구현할 계획이었습니다.) 재설정 버튼을 누를 때 모든 ‘라이브’객체를 파괴 할 수 있도록 모든 ‘재설정 가능한’객체가 동일한 클래스에 있도록 프로그램을 구성했습니다.

데이터를 역 참조하고 가비지 수집기가 데이터를 수집 할 때까지 기다렸다면 사용자가 데이터를 반복해서 입력하고 재설정 버튼을 누르면 메모리 누수가 발생하지 않습니까? 또한 Java가 언어로서 매우 성숙하기 때문에 이러한 일이 발생하지 않도록하거나 이것을 올바르게 처리하는 방법이 있어야한다고 생각했습니다.



답변

Java는 가비지 수집 언어이므로 객체가 언제 언제 파괴되는지 예측할 수 없습니다. 따라서 소멸자와 직접적으로 동등한 것은 없습니다.

상속 된 메소드 finalize가 있지만 가비지 수집기의 재량에 따라 완전히 호출됩니다. 따라서 명시 적으로 정리 해야하는 클래스의 경우 규칙은 close 메소드 를 정의하고 온 전성 검사에만 마무리를 사용하는 것입니다 (즉, close 가 호출되지 않은 경우 지금 수행하고 오류를 기록하십시오).

최근 에 Finalize대한 심도있는 토론을 제기 한 질문 이 있었 으므로 필요한 경우 더 깊이를 제공해야합니다 …


답변

try-with-resources 문을 살펴 보십시오 . 예를 들면 다음과 같습니다.

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

여기서 더 이상 필요하지 않은 자원은 BufferedReader.close()메소드 에서 해제됩니다 . AutoCloseable비슷한 방식으로 구현 하고 사용하는 자체 클래스를 만들 수 있습니다 .

이 문장은 finalize코드 구조화 측면에서 보다 더 제한적 이지만 동시에 코드를 이해하고 유지하기가 더 간단 해집니다. 또한 finalize응용 프로그램을 실행하는 동안 메서드 가 전혀 호출 되지 않을 수도 있습니다.


답변

아니, 여기에 소멸자가 없습니다. 그 이유는 모든 Java 오브젝트가 힙 할당되고 가비지 수집되기 때문입니다. 명시 적 할당 해제 (예 : C ++의 삭제 연산자)가 없으면 실제 소멸자를 구현하는 현명한 방법이 없습니다.

Java는 종료자를 지원하지만 소켓, 파일 핸들, 창 핸들 등과 같은 기본 자원에 대한 핸들을 보유하는 오브젝트에 대한 보호 수단으로 만 사용됩니다. 가비지 콜렉터는 종료 자없이 오브젝트를 수집 할 때 단순히 메모리를 표시합니다. 지역은 자유롭고 그게 다야. 객체에 finalizer가 있으면 먼저 임시 위치에 복사되고 (여기서 가비지 수집 중임을 나타냄) 최종 처리 대기중인 큐에 대기 한 다음 Finalizer 스레드가 우선 순위가 매우 낮은 큐를 폴링합니다. 종료자를 실행합니다.

응용 프로그램이 종료되면 보류중인 개체가 완료 될 때까지 기다리지 않고 JVM이 중지되므로 종료자가 실행되는 것을 실제로 보장 할 수 없습니다.


답변

finalize () 메소드 사용은 피해야합니다. 리소스 정리를위한 신뢰할 수있는 메커니즘이 아니며 가비지 수집기에서 문제를 일으켜 문제를 일으킬 수 있습니다.

객체에 할당 해제 호출이 필요한 경우 (예 : 리소스 해제) 명시 적 메서드 호출을 사용하십시오. 이 규칙은 기존 API (예 : Closeable , Graphics.dispose () , Widget.dispose () ) 에서 볼 수 있으며 일반적으로 try / finally를 통해 호출됩니다.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

폐기 된 객체를 사용하려고하면 런타임 예외가 발생해야합니다 ( IllegalStateException 참조 ).


편집하다:

데이터를 역 참조하고 가비지 수집기가 데이터를 수집하기를 기다리는 것만으로도 사용자가 데이터를 반복적으로 입력하고 재설정 버튼을 누르면 메모리 누수가 발생하지 않을 것이라고 생각했습니다.

일반적으로 객체를 역 참조하기 만하면됩니다. 최소한 이것이 작동하는 방식입니다. 가비지 콜렉션이 걱정되면 Java SE 6 HotSpot ™ 가상 머신 가비지 콜렉션 튜닝 (또는 JVM 버전의 해당 문서)을 확인하십시오.


답변

Java 1.7이 릴리스되면 이제 try-with-resources블록 을 사용하는 추가 옵션이 있습니다. 예를 들어

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing...");
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying...");
            throw new Exception("throwing...");
        }
        catch (Exception e) {
            System.out.println("catching...");
        }
        finally {
            System.out.println("finalizing...");
        }
    }
}

이 클래스를 c.close()실행하면 try블록이 남아 있을 때 catchfinally블록이 실행 되기 전에 실행됩니다. finalize()메소드 의 경우와 달리 close()실행이 보장됩니다. 그러나 finally절 에서 명시 적으로 실행할 필요는 없습니다 .


답변

나는 finalize의 실행에 의존하지 말라고 다른 답변에 전적으로 동의합니다.

try-catch-finally 블록 외에도 Runtime # addShutdownHook (Java 1.3에 도입)을 사용하여 프로그램에서 최종 정리를 수행 할 수 있습니다.

소멸자와 동일하지 않습니다 수행되는 정리 메소드 (영구 데이터베이스 연결 닫기, 파일 잠금 제거 등)를 호출 할 수있는 리스너 객체가 등록 된 종료 후크를 구현할 수 있습니다 . 소멸자 . 다시 말하지만 이것은 소멸자를 대체하지 않지만 경우에 따라 원하는 기능에 접근 할 수 있습니다.

이것의 장점은 프로그램의 나머지 부분에서 해체 동작이 느슨하게 결합 되어 있다는 것입니다.


답변

아니요, java.lang.Object#finalize가장 가까운 곳입니다.

그러나 언제 호출되는지는 보장되지 않습니다.
보다:java.lang.Runtime#runFinalizersOnExit(boolean)