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


330

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


34
참고로 : finalize는 Java 9
Reg


어떤 것이 객체 또는 클래스에 대한 참조가있는 경우. finalize()가비지 콜렉션은 영향을 미치지 않습니다.
ha9u63ar

답변:


273

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

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

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

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

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


19
다시 말해서 (미래의 독자를 위해 명확히하기 위해) 메인 클래스가 닫힐 때 쓰레기를 수집 할 필요가 없으므로 메인 클래스에서 호출되지 않습니다. OS는 앱이 사용한 모든 것을 정리합니다.
Mark Jeronimus

113
"사용하기에 가장 좋은 방법은 아닙니다 ... 필요한 것이 없다면, 그 문장은 모든 것의 100 %에 적용되므로 도움이되지 않습니다." Joachim Sauer의 답변이 훨씬 좋습니다
BT

1
@ Zom-B 당신의 예제는 설명에 도움이되지만, 단지 놀랄만 한 것입니다. 아마도 메인 클래스가 데몬이 아닌 스레드를 만든 다음 반환하면 메인 클래스에서 호출 될 수 있습니까?
Tom G

3
그렇다면 finalize유용한 상황은 무엇 입니까?
nbro

3
@MarkJeronimus-사실, 그것은 관련이 없습니다. finalize()클래스의 인스턴스 << >> 쓰레기가 아닌 경우 주요 방법이 종료되면 수집 된 기본 클래스의 메소드가 호출된다. 게다가 메인 클래스 는 응용 프로그램이 완료되기 전에 가비지 수집 될 있습니다. 예를 들어 "메인"스레드가 다른 스레드를 만든 다음 반환하는 다중 스레드 응용 프로그램에서. (실제로 비표준 클래스 로더가 필요합니다 ....)
Stephen C

379

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

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

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

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


2
@Rajesh. 아니요. "수명"문제가 아닙니다. 프로그램을 무한 루프 (수년간)에 ​​넣을 수 있으며 가비지 수집기가 필요하지 않으면 절대 실행되지 않습니다.
ChrisCantrell

5
@VikasVerma : 완벽한 대체품은 아무것도 아닙니다. 필요하지 않습니다. 이해가되는 유일한 경우는 클래스가 외부 리소스 (예 : TCP / IP 연결, 파일 ... Java GC가 처리 할 수없는 것)를 관리하는 경우입니다. 이 경우 Closable인터페이스 (및 그 배후의 아이디어)는 아마도 당신이 원하는 것입니다 : .close()리소스를 닫거나 버리고 클래스 사용자가 적시에 호출하도록 요구합니다. 당신은 할 수 추가 할 finalize방법 "단지 저장 될"을하지만, (믿을 충분하지 않습니다 때문에) 그 실제 수정보다 더 디버깅 도구가 될 것입니다.
Joachim Sauer 2018 년

4
@Dragonborn : 실제로는 다른 질문이며 별도로 문의해야합니다. 종료 후크가 있지만 JVM이 예기치 않게 종료 된 경우 (일명 충돌) 보장되지 않습니다. 그러나 그들의 보증은 파이널 라이저보다 훨씬 강력합니다 (그리고 더 안전합니다).
Joachim Sauer 2019

4
마지막 단락에서는 리소스를 호출한다고 보장 할 수는 없지만 리소스를 정리하는 용도로만 사용한다고 말합니다. 이 낙관론이 말하는가? 리소스를 정리하는 데 적합하지 않기 때문에 신뢰할 수없는 것으로 가정합니다.
Jeroen Vannevel

2
파이널 라이저는 때때로 하루를 절약 할 수 있습니다 ... 타사 라이브러리가 FileInputStream을 사용하고 닫지 않은 경우가 있습니다. 내 코드는 라이브러리의 코드를 호출 한 다음 파일이 열려 있기 때문에 파일을 이동하려고했습니다. System.gc()FileInputStream :: finalize ()를 호출 하도록 강제 로 호출 한 다음 파일을 이동할 수 있습니다.
Elist

73
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

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


25
링크 된 JavaWorld 기사는 1998 년에 작성되었으며 흥미로운 조언이 있습니다. 특히 JVM이 종료되기 전에 종료자가 실행되도록 System.runFinalizersOnExit ()를 호출하는 제안이 있습니다. 이 방법은 현재 사용되지 않으며 '이 방법은 본질적으로 안전하지 않습니다. 다른 스레드가 동시에 해당 객체를 조작하여 불규칙한 동작이나 교착 상태가 발생하는 동안 최종 객체가 라이브 객체에서 호출 될 수 있습니다. ' 그래서 나는 그렇게하지 않을 것입니다.
Greg Chabala

3
runFinalizerOnExit ()는 스레드로부터 안전하지 않기 때문에 Runtime.getRuntime (). addShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); 클래스의 생성자에서.
Ustaman Sangat

2
@Ustaman Sangat 그렇게하는 방법이지만, shutdownHook에서 인스턴스에 대한 참조를 설정한다는 점을 기억하십시오. 이는 클래스가 가비지 수집되지 않도록 보장합니다. 즉, 메모리 누수입니다.
pieroxy

1
@ pieroxy, 나는 여기에 다른 사람에게 finalize ()를 사용하지 않는 것에 관해 동의하지만, 왜 종료 후크에서 참조가 필요한지 알 수 없습니다. 하나는 부드러운 참조를 가질 수 있습니다.
Ustaman Sangat

25

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

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

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

20

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
}

3
try-with-resources를 사용하십시오
Gabriel Garcia

3
이것은 객체의 수명이 하나의 기능 범위에 있다고 가정합니다. 물론 OP가 언급하는 경우가 아니며 기본적으로 모든 사람이 필요로하는 경우도 아닙니다. "캐시 엔진 리턴 값 참조 카운트"를 생각하십시오. 마지막 심판이 해제 될 때 캐시 항목을 해제하려고하지만 마지막 심판이 언제 해제되는지 알 수 없습니다. finalize ()는 예를 들어 참조 횟수를 줄일 수 있지만 사용자가 명시 적으로 무료 함수를 호출 해야하는 경우 메모리 누수를 요구합니다. 일반적으로 나는 단지 두 가지를 모두 수행합니다 (릴리스 기능 + 최종 확인에서 이중 확인 ...) ...
Erik Aronesty

16

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에 의해 종료 큐에 배치되지만 테스트가 완료되기 전에 완료가 완료되지 않습니다.

10

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를 지 울지 여부가 불확실합니다.


10
호출하면 System.gc();가비지 콜렉션이 실제로 실행되는 것을 보장하는 것은 아닙니다.
Simon Forsberg

3
어떤 종류 의 수집이 실행 될지는 보장되지 않습니다 . 대부분의 Java GC는 "세대"수집기이므로 관련이 있습니다.
Stephen C

5

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

4

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

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

최종 생각

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


2

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

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

final느린 계산 중에 객체 의 필드가 반복적으로 사용되고 그 이후에 객체가 사용되지 않으면 소스 코드가 필드를 요청할 때까지 객체가 계속 유지되거나 JIT가 필드를 임시 변수를 계산 한 다음 계산하기 전에 객체를 포기 하시겠습니까?
supercat

@supercat : 옵티마이 저는 객체가 처음 생성되지 않은 형태로 코드를 다시 쓸 수 있습니다. 이 경우 동기화가 객체 사용과 종료 자 사이에서 순서를 강제하지 않으면 생성자가 완료된 직후에 완료 될 수 있습니다.
Holger

@Holger : JIT가 생성과 포기 사이의 객체에 발생하는 모든 것을 볼 수있는 경우 JIT가 파이널 라이저를 일찍 시작해야 할 이유가 없습니다. 실제 질문은 종료자가 특정 방법 내에서 실행되지 않도록하기 위해 코드에서 수행해야하는 작업입니다. .NET에는 GC.KeepAlive()GC가 객체를 사용할 수 있다고 가정하는 것 외에는 아무것도하지 않는 기능이 있지만 Java에서는 그러한 기능을 알지 못합니다. volatile그 목적으로 변수를 사용할 수는 있지만 그러한 목적으로 만 변수를 사용하면 낭비가 될 것입니다.
supercat

@ supercat : JIT는 종료를 발생시키지 않으며 참조를 유지하지 않도록 코드를 정렬하지만 직접을 대기열에 넣는 것이 유리 할 수 ​​있으므로 FinalizerReferenceGC주기가 필요하지 않습니다. 참조. 동기화는 발생 전 관계 를 보장하기에 충분합니다 . 마무리는 다른 스레드에서 (실제로) 실행될 수 있기 때문에 어쨌든 공식적으로 필요합니다. Java 9가 추가 될 예정입니다 Reference.reachabilityFence.
Holger

@Holger : JIT가 객체 생성을 최적화하는 Finalize경우 JIT가 직접 코드를 생성 한 경우 에만 호출됩니다. 단일 스레드에서만 사용될 것으로 예상되는 객체에 대해 일반적으로 동기화 코드가 필요합니까? 객체가 버리기 전에 취소해야하는 작업을 수행하는 경우 (예 : 소켓 연결 열기 및 다른 쪽 리소스에 대한 독점 사용 획득) 코드가 여전히 소켓을 사용하는 동안 종료자가 연결을 닫으면 재앙이됩니다 . 코드가 동기화를 사용하는 것이 정상
일까요

2

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


3
잘못되었습니다. 당신이 말하는 것은 객체가 도달 할 수 없게되면 완성된다는 것입니다. 실제로 메소드가 수집 될 때 호출됩니다.
Stephen C

2

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

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

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


1

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 메소드가 호출됩니다.


0

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

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

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

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

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

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

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

출처


0

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

예:

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


0

https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers 에서 지적했듯이 ,

실행 시간은 JVM (Java Virtual Machine)에 따라 다르므로 종료자를 실행해야하는 고정 시간은 없습니다. 유일한 보장은 실행되는 모든 finalizer 메소드가 연관된 오브젝트에 도달 할 수없는 후 (가비지 콜렉션의 첫 번째주기 동안 발견됨) 가비지 콜렉터가 연관된 오브젝트의 스토리지를 회수하기 전에 (가비지 컬렉터의 두 번째주기 동안) 그렇게하는 것입니다. . 객체에 도달 할 수 없게 된 후 객체의 파이널 라이저 실행이 임의로 오랜 시간 지연 될 수 있습니다. 결과적으로, 객체의 finalize () 메소드에서 파일 핸들을 닫는 것과 같이 시간이 중요한 기능을 호출하는 것은 문제가됩니다.


-3

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

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();
            }
     }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.