종료 클래스 자바 Java에서 finalize () 메서드는 언제 호출됩니까?




8 Answers

finalize 메소드는 객체가 가비지 수집하려고 할 때 호출됩니다. 가비지 수집 대상이 된 후에는 언제든지 가능합니다.

객체가 결코 가비지 수집되지 않을 가능성이 있습니다 (따라서 finalize 는 호출되지 않습니다). 이것은 객체가 gc에 적합하지 않을 때 (JVM의 전체 수명 기간 동안 도달 할 수 있기 때문에) 또는 객체가 적격 해지는 시간과 JVM이 실행을 멈추는 시간 사이에 실제로 가비지 콜렉션이 실행되지 않을 때 발생할 수 있습니다. 테스트 프로그램).

JVM이 아직 호출되지 않은 객체에 대해 finalize 를 실행하도록 지시하는 방법이 있지만,이 메소드를 사용하는 것은 좋지 않습니다 (해당 메소드의 보장도 그리 강력하지 않습니다).

응용 프로그램의 올바른 작동을 위해 finalize 작업을하는 경우에는 잘못된 작업을 수행하고있는 것입니다. finalize 는 (보통 Java가 아닌) 자원을 정리할 때만 사용해야합니다. JVM이 모든 객체에서 finalize 가 호출되는 것을 보장하지 않기 때문입니다.

effective java finalizer

finalize() 메서드가 JVM 에서 호출 될 때를 알아야합니다. finalize() 메서드가 재정의되어 호출 될 때 파일에 쓰는 테스트 클래스를 만들었습니다. 그것은 실행되지 않습니다. 아무도 그것이 왜 실행되지 않는 이유를 말해 줄 수 있습니까?




Java finalize() 메서드는 소멸자가 아니므로 응용 프로그램이 의존하는 논리를 처리하는 데 사용해서는 안됩니다. Java 사양에는 응용 프로그램의 수명주기 동안 finalize 메서드가 전혀 호출되지 않는다고 명시되어 있습니다.

당신이 바라는 것은 finally 와 정리 방법의 조합입니다 :

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}



Java에서 finalize() 메서드는 언제 호출됩니까?

finalize 메소드는 GC가 객체가 더 이상 도달 할 수 없다는 것을 감지하고 실제로 객체가 사용하는 메모리를 회수하기 전에 호출됩니다.

  • 객체가 도달 할 수 없게되면 finalize() 가 결코 호출되지 않습니다.

  • GC가 실행되지 않으면 finalize() 가 호출되지 않을 수 있습니다. 일반적으로 GC는 JVM이 쓸모있는 쓰레기가 될 것이라고 판단 할 때만 실행됩니다.

  • GC가 특정 개체에 도달 할 수 없다고 판단하기 전에 하나 이상의 GC주기가 소요될 수 있습니다. (Java GC는 일반적으로 "generational"컬렉터입니다 ...)

  • GC가 도달 할 수없고 종료 가능한 개체를 발견하면 완료 대기열에 저장됩니다. 종료는 일반적으로 일반 GC와 비동기 적으로 발생합니다.

(실제로 JVM 스펙은 오브젝트가 사용하는 공간을 되찾지 않는 한, JVM이 파이널 라이저를 절대로 실행하지 못하도록합니다.이 방법으로 구현 된 JVM은 불구하고 쓸모 없지만이 동작은 "허용됨"입니다. .)

결말은 명확한 시간 프레임에서 완료되어야하는 일을하기 위해 최종 결정에 의존하는 것이 현명하지 않다는 것입니다. 그것들을 전혀 사용하지 않는 것이 "우수 사례"입니다. finalize() 메서드에서 수행하려고 시도하는 모든 작업을 수행하는 더 나은 (즉,보다 안정적인) 방법이 있어야합니다.

최종화를위한 유일한 합법적 인 사용은 응용 프로그램 코드에 의해 손실 된 객체와 관련된 자원을 정리하는 것입니다. 그럼에도 불구하고 처음부터 객체를 잃어 버리지 않도록 애플리케이션 코드를 작성해야합니다. 예를 들어 close() 가 항상 호출되도록 Java 7+ try-with-resources 를 사용하면 ...)

finalize () 메서드가 재정의되어 호출 될 때 파일에 쓰는 테스트 클래스를 만들었습니다. 그것은 실행되지 않습니다. 아무도 그것이 왜 실행되지 않는 이유를 말해 줄 수 있습니까?

말할 것도 없지만 몇 가지 가능성이 있습니다.

  • 객체는 여전히 도달 할 수 있기 때문에 가비지 수집되지 않습니다.
  • 테스트가 끝나기 전에 GC가 실행되지 않기 때문에 개체가 가비지 수집되지 않습니다.
  • GC에 의해 객체가 발견되고 GC에 의해 완료 대기열에 배치되지만 테스트가 끝나기 전에 마무리 작업이 완료되지 않습니다.



finalize는 클래스 생성을위한 카운트를 출력합니다.

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

본관

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

보시다시피. 다음은 클래스 카운트가 36 일 때 처음 실행 된 GC를 보여줍니다.

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F



오브젝트가 살아있는 스레드 또는 정적 참조로부터 도달 할 수 없다면 오브젝트가 가비지 콜렉션 또는 GC의 대상이됩니다. 즉, 모든 참조가 널인 오브젝트가 가비지 콜렉션에 적합하게된다고 말할 수 있습니다. 순환 종속성은 참조로 간주되지 않습니다. 따라서 오브젝트 A가 오브젝트 B의 참조를 갖고 오브젝트 B가 오브젝트 A의 참조를 가지며 다른 라이브 참조를 가지지 않으면 오브젝트 A와 B 모두 가비지 콜렉션에 적합합니다. 일반적으로 객체는 다음과 같은 경우 Java에서 가비지 컬렉션의 대상이됩니다.

  1. 해당 객체의 모든 참조는 명시 적으로 null로 설정됩니다 (예 : object = null).
  2. 객체는 블록 내부에서 생성되고 일단 제어가 블록을 벗어나면 참조가 범위 밖으로 나옵니다.
  3. 객체가 다른 객체의 참조를 보유하고 부모 객체가 null로 설정된 경우 컨테이너 객체의 참조 null을 설정하면 자식 또는 포함 된 객체가 자동으로 가비지 수집 대상이됩니다.
  4. WeakHashMap을 통해 객체에 라이브 참조 만있는 경우 가비지 수집을받을 수 있습니다.



때로는 파괴되면 개체가 행동을해야합니다. 예를 들어, 객체에 파일 핸들이나 글꼴과 같은 Java 이외의 리소스가있는 경우 객체를 삭제하기 전에 이러한 리소스가 해제되었는지 확인할 수 있습니다. 이러한 상황을 관리하기 위해 java는 "마무리"라는 메커니즘을 제공합니다. 이를 마무리하면 개체가 가비지 수집기에서 제거 될 때 발생하는 특정 동작을 정의 할 수 있습니다. 파이널 라이저를 클래스에 추가하려면 단순히 finalize () 메소드를 정의하십시오. Java 실행 시간은 해당 클래스의 객체를 삭제하려고 할 때마다이 메소드를 호출합니다. finalize 메서드 () 내에서 객체를 삭제하기 전에 수행 할 작업을 지정합니다. 가비지 컬렉터는 주기적으로 실행 상태를 참조하지 않는 객체 또는 참조를 통해 간접적으로 다른 객체를 검색합니다. 자산이 릴리스되기 전에 Java 런타임은 오브젝트에 대해 finalize () 메소드를 호출합니다. finalize () 메서드는 다음과 같은 일반 형식을가집니다.

protected void finalize(){
    // This is where the finalization code is entered
}

protected 키워드를 사용하면 클래스 외부의 코드로 finalize () 에 대한 액세스가 차단됩니다. finalize () 가 가비지 콜렉션 직전에 호출된다는 것을 이해하는 것이 중요합니다. 예를 들어, 객체가 스코프를 벗어날 때 호출되지 않습니다. 즉, finalize () 가 언제 실행되는지 알 수 없다는 뜻입니다. 결과적으로, 프로그램은 오브젝트가 사용하는 시스템 자원이나 기타 자원을 비울 수있는 다른 f}을 제공해야합니다. 프로그램을 정상적으로 실행하려면 finalize () 를 사용해서는 안됩니다.




Java를 사용하면 객체가 호출 될 수있는 finalize ()라는 메서드를 구현할 수 있습니다.

가비지 컬렉터가 객체를 수집하려고하면 finalize () 메서드가 호출됩니다.

가비지 컬렉터가 실행되지 않으면 메서드가 호출되지 않습니다.

가비지 컬렉터가 객체를 수집 하지 못하고 다시 실행하려고 하면 메서드가 두 번째로 호출되지 않습니다.

실제로는 실제 프로젝트에서 사용하지 않을 가능성이 큽니다.

그냥 호출되지 않을 수도 있고 확실히 두 번 호출되지 않을 수도 있다는 것을 명심하십시오. finalize () 메서드는 0 번 또는 1 번 실행할 수 있습니다.

다음 코드에서 가비지 컬렉터를 실행할 필요가 없기 전에 프로그램이 종료되기 때문에 finalize () 메서드는 프로그램을 실행할 때 출력을 생성하지 않습니다.

Source




가비지 콜렉션이 객체에 대한 참조가 더 이상 없다고 판단 할 때 객체의 가비지 수집기에 의해 호출됩니다.

서브 클래스는 finalize 메소드를 오버라이드하여 시스템 자원을 처리하거나 다른 정리를 수행합니다.

finalize의 일반적인 규약에서는, Java 가상 머신이, 액션의 결과를 제외하면 (자), 아직 죽지 않고있는 thread에 의해이 오브젝트에 액세스 할 수있는 수단이 없어 졌다고 판단했을 때, 호출됩니다. 최종 완성 될 준비가되어있는 다른 객체 또는 클래스의 완성으로

finalize 메서드는이 객체를 다른 스레드에서 다시 사용할 수있게 만드는 것을 포함하여 모든 작업을 수행 할 수 있습니다.

그러나 finalize의 일반적인 목적은 오브젝트를 취소 불가능하게 버리기 전에 클린업 조치를 수행하는 것입니다. 예를 들어 입출력 연결을 나타내는 객체의 finalize 메서드는 객체가 영구적으로 버려지기 전에 명시 적 I / O 트랜잭션을 수행하여 연결을 끊을 수 있습니다.

Java 프로그램 언어는 어떤 스레드가 주어진 객체에 대해 finalize 메소드를 호출 할지는 보증하지 않습니다. 그러나 finalize를 호출하는 스레드는 finalize가 호출 될 때 사용자가 볼 수있는 동기화 잠금을 보유하지 않습니다. catch되지 않는 예외가 finalize 메소드에 의해 발생되면 예외는 무시되고 해당 객체의 종료가 종료됩니다.

오브젝트에 대해서 finalize 메소드가 불려 가면 (자), Java 가상 머신은, 가능한 액션을 포함 해, 아직 죽지 않고있는 thread에 의해이 오브젝트에 액세스 할 수있는 수단이 없어 졌다고 다시 결정할 때까지, 더 이상의 액션은 행해지 지 않습니다 완성 될 준비가되어있는 다른 객체 또는 클래스에 의해 객체가 폐기 될 수 있습니다.

finalize 메소드는 주어진 객체에 대해 Java 가상 머신에 의해 두 번 이상 호출되지 않습니다.

finalize 메서드에 의해 throw 된 예외가 발생하면이 객체의 종료가 중지되지만 그렇지 않으면 무시됩니다.




Related