Programing

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

lottogame 2020. 3. 9. 08:05
반응형

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


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


일반적으로 finalize()청소 등을하지 않는 것이 가장 좋습니다 .

에 따르면 자바 독 (그것이 가치가 독서 것)이 있습니다 :

가비지 수집에서 객체에 대한 참조가 더 이상 없음을 확인할 때 객체의 가비지 수집기에 의해 호출됩니다.

Joachim이 지적했듯이, 객체에 항상 액세스 할 수 있다면 프로그램 수명 중에는 결코 일어날 수 없습니다.

또한 가비지 수집기는 특정 시간에 실행되도록 보장되지 않습니다. 일반적으로, 내가 말하려는 finalize()것은 아마도 당신이 필요로하는 특별한 것이 없다면 일반적으로 사용하는 가장 좋은 방법은 아닐 것입니다.


finalize객체에 대한 쓰레기 수집 얻을 때 메서드가 호출됩니다. 가비지 수집 대상이 된 후 언제든지 가능합니다.

객체는 절대 가비지 수집 finalize되지 않으므로 호출되지 않을 수도 있습니다. 이는 객체가 gc를 사용할 수없는 경우 (JVM의 전체 수명 동안 도달 할 수 있기 때문에) 또는 객체가 적합한 시간과 JVM이 실행을 중지하는 시간 사이에 실제로 가비지 콜렉션이 실행되지 않는 경우에 발생할 수 있습니다 (이는 종종 단순하게 발생 함) 테스트 프로그램).

JVM이 finalize아직 호출되지 않은 객체 에서 실행되도록 지시하는 방법이 있지만 사용하지 않는 것이 좋습니다.

finalize응용 프로그램의 올바른 작동에 의존 하면 문제가있는 것입니다. (일반적으로 Java 이외의) 자원을 정리할 때만finalize 사용해야 합니다. 그리고 그건 정확히 JVM이되지 보장 않기 때문에 과거의 어떤 객체에 호출됩니다.finalize


protected void finalize() throws Throwable {}
  • 모든 클래스는 finalize()java.lang.Object 에서 메소드를 상속합니다.
  • 이 메소드는 객체에 대한 참조가 더 이상 없다고 판단되면 가비지 수집기에서 호출합니다.
  • Object finalize 메서드는 작업을 수행하지 않지만 모든 클래스에서 재정의 할 수 있습니다.
  • 일반적으로 비 Java 자원을 정리 (예 : 파일 닫기)하도록 대체해야합니다.
  • 재정의 finalize()하는 경우 try-catch-finally 문을 사용하고 항상을 호출하는 것이 super.finalize()좋습니다. 이것은 클래스를 호출하는 객체가 사용하는 리소스를 실수로 놓치는 일이 없도록 안전 조치입니다

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
    
  • finalize()가비지 수집 중에 발생한 예외 는 종료를 중단하지만 그렇지 않으면 무시됩니다.

  • finalize() 어떤 객체에서도 두 번 이상 실행되지 않습니다

인용 : http://www.janeg.ca/scjp/gc/finalize.html

이 기사를 확인할 수도 있습니다.


Java finalize()메소드는 소멸자가 아니며 애플리케이션이 의존하는 논리를 처리하는 데 사용해서는 안됩니다. Java 사양에 따르면 finalize응용 프로그램을 실행하는 동안 메서드 가 전혀 호출 되지 않을 수도 있습니다.

아마도 당신이 원하는 것은 다음 finally과 같이 정리 방법입니다.

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

Effective Java, 2nd edition page 27을 확인하십시오. 항목 7 : 종료자를 피하십시오

종료자는 예측할 수없고 종종 위험하며 일반적으로 불필요합니다. 파이널 라이저에서 시간 결정적인 작업을 수행하지 마십시오. 중요한 영구 상태를 업데이트하기 위해 종료 자에 의존하지 마십시오.

리소스를 종료하려면 try-finally를 대신 사용하십시오.

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}

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

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

  • 객체에 도달 할 수없는 경우 finalize()절대로 호출되지 않습니다.

  • GC가 실행되지 않으면 finalize()호출되지 않을 수 있습니다. 일반적으로 GC는 JVM에서 가비지가 충분하다고 판단 할 때만 실행됩니다.

  • GC가 특정 개체에 도달 할 수없는 것으로 판단하기 전에 두 개 이상의 GC주기가 필요할 수 있습니다. Java GC는 일반적으로 "세대"수집기입니다.

  • GC가 객체에 도달 할 수없고 종료 할 수 있음을 감지하면 최종 큐에 배치됩니다. 마무리는 일반적으로 일반 GC와 비동기 적으로 발생합니다.

(JVM을 사양은 실제로 JVM을은에 결코 .이 오브젝트에 의해 사용되는 공간을 회수하지 않는 것을 제공 ... 실행되지 파이 나라 쓸모 / 불구가 될 것이다 이런 식으로 구현 한 JVM을하지만,이 문제가 "허용"된다 .)

결말은 확정 된 시간 안에해야 할 일을 완수하기 위해 마무리에 의존하는 것이 현명하지 않다는 것입니다. 전혀 사용하지 않는 것이 "모범 사례"입니다. finalize()메소드 에서 수행하려는 모든 작업을 수행하는 더 나은 (즉, 더 안정적인) 방법이 있어야합니다 .

종료를위한 합법적 인 용도는 응용 프로그램 코드에 의해 손실 된 개체와 관련된 리소스를 정리하는 것입니다. 그럼에도 불구하고, 처음부터 객체를 잃지 않도록 애플리케이션 코드를 작성해야합니다. (예를 들어, Java 7+ try-with-resources 를 사용하여 close()항상 호출되도록하십시오.)


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

말하기는 어렵지만 몇 가지 가능성이 있습니다.

  • 개체는 여전히 접근 가능하기 때문에 가비지 수집되지 않습니다.
  • 테스트가 완료되기 전에 GC가 실행되지 않으므로 객체가 가비지 수집되지 않습니다.
  • 개체가 GC에 의해 발견되어 GC에 의해 종료 큐에 배치되지만 테스트가 완료되기 전에 완료가 완료되지 않습니다.

JVM이 finalize () 메소드를 호출 할 때 불확실성이 있기 때문에 (오버라이드 된 finalize ()가 실행되는지 여부를 확실하지 않음), 연구 목적으로 finalize ()가 호출 될 때 발생하는 상황을 관찰하는 더 좋은 방법은 다음과 같습니다. JVM이 명령에 의해 가비지 콜렉션을 강제로 호출하도록합니다 System.gc().

특히 finalize ()는 객체를 더 이상 사용하지 않을 때 호출됩니다. 그러나 새 객체를 만들어 호출하려고 할 때 확실하게 호출 할 수는 없습니다. 따라서 확실하게 미래에 사용되지 않는 null객체 c생성하므로 객체 c의 최종 호출을 볼 수 있습니다.

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

산출

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

– 최대 70까지 인쇄 한 후 프로그램에서 오브젝트 b를 사용하지 않은 후에도 "Bike 클래스의 호출 된 종료 메소드 ..."가 인쇄되지 않으므로 JVM이 b를 지 울지 여부가 불확실합니다.


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

(테스트 중에 연결 풀을 폐기하기 위해) 최근에 종료 자 방법으로 씨름을 했으므로 종료 자에는 많은 것이 부족하다고 말해야합니다. JavaVM 환경 (Oracle JDK, Ubuntu 15)에서는 VisualVM을 사용하여 약한 참조를 사용하여 실제 상호 작용을 추적했습니다.

  • Finalize는 Finalizer (GC 부분)가 개별적으로 참조를 소홀히 소유하는 즉시 호출되지는 않습니다.
  • 기본 가비지 콜렉터는 도달 불가능한 오브젝트를 풀링합니다.
  • 가비지 수집기가 리소스를 해제하는 특정 단계가 있음을 구현 세부 정보를 가리키며 Finalize가 일괄 적으로 호출됩니다.
  • System.gc ()를 호출하면 개체가 더 자주 마무리되지 않고 도달 할 수없는 개체를 더 빨리 인식하게됩니다.
  • 스레드 덤프를 만들면 힙 덤프 나 다른 내부 메커니즘을 수행하는 동안 힙 오버 헤드가 높아져 거의 항상 종료자가 트리거됩니다.
  • 마무리 이음새는 메모리 요구 사항 (더 많은 메모리 확보) 또는 특정 내부 한계의 마무리 증가를 위해 표시되는 개체 목록에 의해 구속됩니다. 따라서 많은 객체가 마무리되면 마무리 단계가 몇 번에 비해 더 자주 트리거됩니다.
  • System.gc ()가 직접 참조를 시작한 상황이 있었지만 참조가 지역적이고 짧은 생활 인 경우에만 가능합니다. 세대와 관련이있을 수 있습니다.

최종 생각

마무리 방법은 신뢰할 수 없지만 한 가지 용도로만 사용할 수 있습니다. 가비지 수집되기 전에 객체를 닫거나 폐기했는지 확인하여 수명 종료 조치와 관련된보다 복잡한 수명주기가있는 객체를 올바르게 처리 할 경우 페일 세이프를 구현할 수 있습니다. 그것이 내가 생각할 수있는 한 가지 이유는 그것을 무시하기 위해 가치가 있습니다.


라이브 스레드 또는 정적 굴절에서 도달 할 수없는 객체는 가비지 콜렉션 또는 GC에 적합합니다. 즉, 모든 참조가 널인 경우 객체가 가비지 콜렉션에 적합하다고 말할 수 있습니다. 순환 종속성은 참조로 계산되지 않으므로 오브젝트 A에 오브젝트 B에 대한 참조가 있고 오브젝트 B에 오브젝트 A에 대한 참조가 있고 다른 라이브 참조가없는 경우 오브젝트 A와 B 모두 가비지 콜렉션에 적합합니다. 일반적으로 다음과 같은 경우 객체가 Java에서 가비지 수집 대상이됩니다.

  1. 해당 객체의 모든 참조는 명시 적으로 null로 설정됩니다. 예 : object = null
  2. 블록 내에서 객체가 생성되고 제어가 해당 블록을 종료하면 참조가 범위를 벗어납니다.
  3. 객체가 다른 객체에 대한 참조를 보유하고 컨테이너 객체의 참조를 null로 설정하면 하위 객체 또는 포함 된 객체가 가비지 수집에 적합하게됩니다.
  4. 개체에 WeakHashMap을 통한 라이브 참조 만있는 경우 가비지 수집이 가능합니다.

finalize 메소드는 보장되지 않습니다.이 메소드는 오브젝트가 GC에 적합 할 때 호출됩니다. 객체가 가비지 수집되지 않는 상황이 많이 있습니다.


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

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

protected 키워드를 사용하면 클래스 외부의 코드 finalize ()액세스 할 수 없습니다. finalize () 는 가비지 수집 직전에 호출 된다는 것을 이해해야합니다 . 예를 들어 객체가 범위를 벗어나면 호출되지 않습니다. finalize ()언제 또는 언제 실행 될지 알 수 없음을 의미합니다 . 결과적으로, 프로그램은 시스템 자원 또는 오브젝트가 사용하는 다른 자원을 해제하기위한 다른 수단을 제공해야합니다. 프로그램을 정상적으로 실행하기 위해 finalize ()의존해서는 안됩니다 .


finalize 메서드를 재정의하는 클래스

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

메소드가 종료 될 가능성

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

메모리에 덤프 객체가 과부하되면 gc는 finalize 메소드를 호출합니다.

메모리가 오버로드되면 finalize 메소드가 호출됩니다. 자주 호출되는 finalize 메소드를 찾지 못하는 콘솔을 실행하십시오.


Java는 객체가 호출 될 수있는 finalize ()라는 메소드를 구현할 수 있도록합니다.

가비지 수집기가 개체를 수집하려고하면 finalize () 메서드가 호출됩니다.

가비지 수집기가 실행되지 않으면 메서드가 호출되지 않습니다.

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

실제로는 실제 프로젝트에서 사용할 가능성이 거의 없습니다.

호출되지 않을 수도 있고 두 번 호출되지 않을 수도 있습니다. finalize () 메소드는 0 회 또는 1 회 실행될 수 있습니다.

다음 코드에서 finalize () 메서드는 가비지 수집기를 실행하기 전에 프로그램이 종료되므로 실행할 때 출력을 생성하지 않습니다.

출처


finalize()가비지 수집 직전에 호출됩니다. 객체가 범위를 벗어날 때 호출되지 않습니다. 즉, 언제 또는 언제 finalize()실행 될지 알 수 없습니다 .

예:

가비지 수집기가 발생하기 전에 프로그램이 종료되면 finalize()실행되지 않습니다. 따라서 프로그램이 정상적인 조작에서 사용하는 수단이 아니라 다른 자원을 올바르게 처리하거나 특수 용도의 응용 프로그램을 위해 백업 절차로 사용해야합니다.


더 나은 이해를 위해이 프로그램을 실행 해보십시오

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}

참고 URL : https://stackoverflow.com/questions/2506488/when-is-the-finalize-method-called-in-java

반응형