[java] 왜 finalize ()를 구현하겠습니까?

나는 많은 신인 Java 질문을 읽었 finalize()으며 아무도 finalize ()가 리소스를 정리하는 신뢰할 수없는 방법이라는 것을 아무도 분명히 알지 못했다는 것을 알게되었습니다. 누군가 Connections를 정리하는 데 사용한다는 의견을 보았습니다 .Connection이 닫혔다는 보장에 가까워 질 수있는 유일한 방법은 마침내 try (catch)를 구현하는 것이므로 정말 무섭습니다.

CS에서 교육을받지는 않았지만 지금은 거의 10 년 동안 전문적으로 Java 프로그래밍을 해왔으며 구현 한 사람을 본 적이 없습니다. finalize() 프로덕션 시스템에서 하는 적이 없습니다. 그렇다고해서 그것이 용도가 없거나 내가 함께 일한 사람들이 올바르게하고 있다는 것을 의미하지는 않습니다.

그래서 제 질문은 어떤 유스 케이스가 구현에 있는지입니다. finalize() 언어 내의 다른 프로세스 또는 구문을 통해보다 안정적으로 처리 할 수없는 을 있습니까?

Java 교과서를 반복하거나 특정 시나리오 나 경험을 제공하십시오. 그렇지 않으면이 질문의 의도가 아닌 finalize의 의도 된 용도로는 충분하지 않습니다.



답변

외부 리소스 (소켓, 파일 등)를 보유한 객체의 백스톱으로 사용할 수 있습니다. close()호출해야하는 메소드 및 문서를 구현하십시오 .

처리가 완료되지 않은 것으로 감지 finalize()되면 close()처리를 구현 하십시오 . 아마도 stderr버그가있는 발신자를 청소하고 있음을 지적 하기 위해 무언가를 버려 두었을 수도 있습니다.

예외적이거나 번잡 한 상황에서 추가 안전을 제공합니다. 모든 발신자가 매번 올바른 일을하는 것은 아닙니다 try {} finally {}. 불행히도 대부분의 환경에서 적용됩니다.

거의 필요하지 않다는 데 동의합니다. 그리고 논평자들이 지적한 바와 같이, 그것은 GC 오버 헤드와 함께 온다. 장기 실행 앱에서 “벨트 및 멜빵”안전이 필요한 경우에만 사용하십시오.

Java 9 Object.finalize()부터는 더 이상 사용되지 않습니다. 그들은 우리를 지적 java.lang.ref.Cleaner하고 java.lang.ref.PhantomReference대안으로.


답변

finalize()지정되지 않은 시간에 코드를 실행하는 것이 좋을 수도 있다는 JVM에 대한 힌트입니다. 이것은 코드가 신비하게 실행되지 않도록하려는 경우에 좋습니다.

파이널 라이저에서 중요한 것을 수행하는 것 (기본적으로 로깅을 제외한 모든 것)도 세 가지 상황에서 좋습니다.

  • 다른 최종 객체는 여전히 프로그램의 나머지 부분이 유효한 것으로 간주됩니다.
  • 종료 후 모든 클래스의 모든 메소드에 많은 검사 코드를 추가하여 종료 후 올바르게 작동하는지 확인하려고합니다.
  • 실수로 완성 된 개체를 부활 시키려고하고, 왜 작동하지 않는지, 그리고 / 또는 결국 릴리스 될 때 왜 끝나지 않는지를 알아 내려고 많은 시간을 할애합니다.

finalize ()가 필요하다고 생각되면 때로는 팬텀 참조가 필요합니다 (이 예제에서는 참조에 의해 사용되는 연결에 대한 하드 참조를 보유하고 팬텀 참조가 대기 한 후에 닫을 수 있습니다). 이것은 또한 신비하게도 절대로 실행되지 않을 수있는 속성을 가지고 있지만 적어도 최종 객체에서 메소드를 호출하거나 부활시킬 수는 없습니다. 따라서 연결을 깨끗하게 닫을 필요는 없지만 상황이 좋을 때도 좋을 것입니다. 클래스의 고객은 직접 연락을 할 수 없거나 전화를 걸 수 없습니다 (실제로 공평합니다- 뭐’ s 수집하기 전에 특정 조치 가 필요한 인터페이스를 설계하는 경우 가비지 콜렉터가 전혀 필요하지 않습니까? 그것은 malloc / free의 시대에 우리를 되돌려 놓는다.)

다른 경우에는 관리하려는 리소스가 더 강력해야합니다. 예를 들어, 왜 해당 연결을 닫아야합니까? 궁극적으로 시스템에서 제공하는 일종의 I / O (소켓, 파일 등)를 기반으로해야하는데, 왜 가장 낮은 수준의 리소스를 확보 할 때 시스템을 닫아 시스템을 닫을 수 없습니까? 다른 쪽 끝의 서버에서 소켓을 떨어 뜨리지 않고 연결을 완전히 닫아야하는 경우 코드가 실행중인 시스템의 전원 케이블을 통해 누군가가 트립되거나 중재 네트워크가 종료되면 어떻게됩니까?

면책 조항 : 나는 과거에 JVM 구현에 종사했습니다. 나는 파이널 라이저가 싫어.


답변

간단한 규칙 : 종료자를 사용하지 마십시오.

객체가 finalizer를 가지고 있다는 사실만으로 (실행 코드에 관계없이) 가비지 수집에 상당한 오버 헤드가 발생하기에 충분합니다.

Brian Goetz 의 기사 에서 :

종료자가있는 객체 (사소한 finalize () 메서드가있는 객체)는 종료자가없는 객체와 비교하여 상당한 오버 헤드가 있으므로 드물게 사용해야합니다. 최종화 가능 객체는 할당 속도가 느리고 수집 속도가 느립니다. 할당시 JVM은 완료 가능 오브젝트를 가비지 콜렉터에 등록해야하며 (최소한 HotSpot JVM 구현에서) 완료 가능 오브젝트는 대부분의 다른 오브젝트보다 느린 할당 경로를 따라야합니다. 마찬가지로, 최종화 가능한 객체도 수집 속도가 느립니다. 종료 가능한 객체를 회수하려면 가비지 수집주기가 2 회 이상 (가장 좋은 경우) 필요하며 가비지 수집기는 마무리 작업을 호출하기 위해 추가 작업을 수행해야합니다. 도달 할 수없는 최종화 가능 오브젝트가 사용하는 메모리가 더 오래 유지되므로 오브젝트를 할당하고 수집하는 데 더 많은 시간이 걸리고 가비지 콜렉터에 더 많은 압력이 가해집니다. 이를 파이널 라이저가 예측 가능한 기간 또는 전혀 실행하지 않을 수 있다는 사실과 결합하면 최종화가 올바른 도구로 사용되는 상황이 상대적으로 적다는 것을 알 수 있습니다.


답변

프로덕션 코드에서 마무리 작업을 사용한 유일한 시간은 주어진 객체의 리소스가 정리되었는지 확인하고 그렇지 않은 경우 매우 성가신 메시지를 기록하는 것입니다. 실제로 시도하지 않았고 제대로 수행되지 않으면 크게 외쳤습니다. 매우 유용한 것으로 판명되었습니다.


답변

1998 년부터 전문적으로 Java를 해왔으며 구현 한 적이 없습니다 finalize(). 한 번도 아닙니다.


답변

받아 들인 대답은 좋았습니다. 지금은 실제로 전혀 사용하지 않고 마무리 기능을 가질 수있는 방법이 있다고 덧붙였습니다.

“참조”클래스를보십시오. 약한 참조, 팬텀 참조 및 소프트 참조.

그것들을 사용하여 모든 객체에 대한 참조를 유지할 수는 있지만이 참조는 GC를 중지시키지 않습니다. 이것에 대한 깔끔한 점은 삭제 될 때 메소드를 호출하도록 할 수 있으며이 메소드 가 호출 되도록 보장 할 수 있다는 것입니다.

마무리에 관해서 : 어떤 객체가 해제되었는지 이해하기 위해 finalize를 한 번 사용했습니다. 스태틱, 레퍼런스 카운팅 등을 사용하여 깔끔한 게임을 할 수는 있지만 분석만을위한 것이지만 다음과 같은 코드를주의해서 살펴보십시오 (마지막뿐만 아니라 가장 가능성이 높은 곳).

public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}

누군가 자신이하는 일을 몰랐다는 신호입니다. 이와 같은 “정리”는 거의 필요하지 않습니다. 수업이 GC되면 자동으로 이루어집니다.

마무리에서 이와 같은 코드를 찾으면 코드를 작성한 사람이 혼란스러워 할 것입니다.

다른 곳이라면 코드가 잘못된 모델에 대한 유효한 패치 일 수 있습니다 (클래스는 오랫동안 머물러 있고 어떤 이유로 든 객체가 GC되기 전에 수동으로 해제해야했습니다). 일반적으로 누군가 리스너 또는 무언가를 제거하는 것을 잊어 버렸고 왜 객체가 GC가 아닌지 알아낼 수 없기 때문에 참조하는 것을 삭제하고 어깨를 으 walk하고 멀리합니다.

“Quicker”를 정리하는 데 사용해서는 안됩니다.


답변

이걸로 무엇을 만들 수 있을지 모르겠지만 …

itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41

내가 추측 그래서 태양은 발견 일부 가 사용되어야한다 (그들이 생각하는) 경우를.