왜 finalize()를 구현합니까?
Java의 신참 질문들을 많이 읽어봤는데finalize()
finalize()가 자원을 청소하는 신뢰할 수 없는 방법이라는 사실을 아무도 명확히 밝히지 않은 것이 다소 당혹스럽다.누군가 Connections를 사용하여 Connections를 청소하는 것을 보았습니다.Connection이 닫혔다는 보장에 근접할 수 있는 유일한 방법은 최종적으로 try(catch)를 구현하는 것이기 때문에 매우 무섭습니다.
CS에서 교육을 받은 적은 없지만, 10년 가까이 자바에서 전문적으로 프로그래밍을 해 왔습니다.실행하는 사람은 본 적이 없습니다.finalize()
생산 시스템에 있어 가장 큰 성과입니다.이것은 여전히 그것이 쓸모가 없다는 것을 의미하거나 나와 함께 일했던 사람들이 그것을 제대로 해왔다는 것을 의미하지는 않는다.
여기서 궁금한 점은 이 시스템을 구현하기 위해 어떤 사용 사례가 있는가 하는 것입니다.finalize()
언어 내의 다른 프로세스 또는 구문을 통해 보다 안정적으로 처리할 수 없는 경우
구체적인 시나리오나 경험을 제시해 주십시오.단순히 Java 교재를 반복하거나 최종 사용으로는 불충분합니다.이 질문의 의도는 아닙니다.
외부 리소스(소켓, 파일 등)를 보유한 개체의 백스톱으로 사용할 수 있습니다.의 실장close()
호출할 필요가 있는 메서드 및 문서.
시행하다finalize()
을 하다close()
처리되지 않은 것을 감지하면 처리됩니다.어쩌면 뭔가 버려지는 게 있을 수도 있고stderr
마차를 몰고 온 사람 뒤처리를 하고 있다는 걸 지적하는 거죠
예외적/불량 시 안전성이 더욱 높아집니다.모든 발신자가 올바른 조치를 취하지는 않습니다.try {} finally {}
항상 채워야 해아쉽지만 대부분의 환경에서 해당됩니다.
거의 필요하지 않다는 것에 동의합니다.코멘트가 지적하고 있듯이 GC 오버헤드가 포함되어 있습니다.장시간 실행되는 앱에서 "벨트와 멜빵" 안전이 필요한 경우에만 사용하십시오.
Java 9부터는 더 이상 사용되지 않는군요!그들은 우리에게 대안으로 제시합니다.
finalize()
는 코드를 지정되지 않은 시간에 실행하는 것이 좋다는 것을 JVM에 시사하는 것입니다.코드 실행이 이상하게 실패하도록 하려면 이 방법이 좋습니다.
최종자에서 중요한 작업(기본적으로 로깅을 제외한 모든 작업)도 다음 세 가지 상황에서 수행할 수 있습니다.
- 다른 최종 객체가 프로그램의 나머지 부분에서 유효하다고 간주되는 상태에 있을 것이라는 도박을 할 수 있습니다.
- 파이널라이저가 있는 모든 클래스의 메서드에 체크 코드를 많이 추가하여 파이널라이즈 후에 올바르게 동작하는지 확인하려고 합니다.
- 완성된 오브젝트를 우연히 부활시키고, 그것들이 왜 동작하지 않는지, 그리고/또는 그것들이 최종적으로 출시되었을 때 왜 완성되지 않는지 알아내기 위해 많은 시간을 할애해야 한다.
final()이 필요하다고 생각되는 경우 실제로 필요한 것은 팬텀 참조일 수 있습니다(이 예에서는 레퍼랜드에서 사용되는 연결에 대한 하드 참조가 유지되고 팬텀 참조가 큐잉된 후 닫힐 수 있습니다.또한 이 기능은 불가사의하게 실행되지 않을 수도 있지만, 적어도 완성된 오브젝트에 대해 메서드를 호출하거나 부활시킬 수는 없습니다.따라서 접속을 완전히 종료할 필요는 없지만 종료하고 싶은 경우 클래스 클라이언트는 스스로 종료할 수 없거나 종료할 수 없는 상황에 적합합니다(실제로 이것은 충분히 공평합니다.즉, 특정 액션이 필요한 인터페이스를 설계할 경우 가비지 콜렉터를 사용하는 것이 무슨 의미가 있습니까?콜렉션으로요?이는 우리를 malloc/free의 시대로 되돌아가게 할 뿐입니다.)
또, 보다 견고한 자원을 필요로 하는 경우도 있습니다.예를 들어, 왜 그 연결을 닫아야 합니까?궁극적으로 시스템에서 제공하는 I/O(소켓, 파일 등)를 기반으로 해야 하는데, 가장 낮은 수준의 리소스가 할당될 때 시스템을 사용하여 종료할 수 없는 이유는 무엇입니까?소켓을 떨어뜨리는 것이 아니라 접속을 확실히 닫아야 하는 경우는 코드를 실행하고 있는 머신의 전원 케이블에 걸려 넘어지거나 간섭하는 네트워크가 끊어지면 어떻게 됩니까?
면책사항:과거에 JVM 구현에 종사한 적이 있습니다.난 파이널라이저가 싫어
간단한 규칙: 절대 최종자를 사용하지 마십시오.
오브젝트에 (실행하는 코드에 관계없이) 최종자가 있다는 사실만으로도 가비지 수집에 상당한 오버헤드가 발생하기에 충분합니다.
Brian Goetz의 기사에서:
finalizer가 있는 오브젝트(중요하지 않은 finalize() 메서드를 가진 오브젝트)는 finalizer가 없는 오브젝트에 비해 오버헤드가 크므로 신중하게 사용해야 합니다.완료 가능한 개체는 할당 속도가 느리고 수집 속도도 느립니다.할당 시 JVM은 완료 가능한 개체를 가비지 컬렉터에 등록해야 하며, 완료 가능한 개체는 대부분의 다른 개체보다 느린 할당 경로를 따라야 합니다.마찬가지로 최종 객체도 수집 속도가 느립니다.완료 가능한 개체를 회수하려면 최소 두 개의 가비지 수집 사이클(최적의 경우)이 필요하며 가비지 수집기는 피니셔를 호출하기 위해 추가 작업을 수행해야 합니다.그 결과 도달할 수 없는 완료 가능한 개체에 사용되는 메모리가 더 오래 유지되기 때문에 개체 할당 및 수집에 더 많은 시간이 걸리고 가비지 수집기에 대한 부담이 증가합니다.이와 더불어 파이널라이저는 예측 가능한 시간 내에 또는 전혀 실행되지 않으며 파이널라이즈가 적절한 도구인 경우가 상대적으로 적다는 것을 알 수 있습니다.
프로덕션 코드에서 finalize를 사용한 것은 특정 객체의 리소스가 정리되었는지 확인하고, 정리되지 않은 경우 매우 음성적인 메시지를 기록하는 것뿐입니다.실제로 시도도 안 하고 제대로 안 되면 소리만 많이 질렀어요.꽤 유용하게 쓰였던 것 같아요
1998년부터 Java를 전문적으로 사용해 왔습니다만, 지금까지 구현해 본 적은 없습니다.finalize()
단 한 번도.
받아들여진 답변은 좋습니다.이제 실제로 사용하지 않고 finalize 기능을 사용할 수 있는 방법이 생겼다는 것을 덧붙이고 싶었습니다.
"참조" 수업을 보세요.약한 레퍼런스, 팬텀 레퍼런스 및 소프트 레퍼런스.
모든 객체에 대한 참조를 유지하기 위해 이러한 참조를 사용할 수 있지만 이 참조만 사용해도 GC는 중지되지 않습니다.여기서 좋은 점은 삭제될 때 메서드를 호출하도록 할 수 있으며 이 메서드는 호출할 수 있다는 것입니다.
최종 결정 사항:어떤 오브젝트가 해방되어 있는지 알기 위해 finalize를 사용한 적이 있습니다.스태틱스, 레퍼런스 카운트 등을 사용하여 깔끔한 게임을 할 수 있지만 분석용일 뿐이지만 다음과 같은 코드(완결판뿐만 아니라 바로 이 부분에서 볼 수 있습니다)에 주의해 주십시오.
public void finalize() {
ref1 = null;
ref2 = null;
othercrap = null;
}
그것은 누군가가 그들이 무엇을 하고 있는지 몰랐다는 징조이다.이런 '정리'는 사실상 전혀 필요하지 않습니다.클래스가 GC'd일 경우 이 작업은 자동으로 수행됩니다.
만약 당신이 최종 단계에서 그러한 코드를 발견한다면, 그것을 쓴 사람이 혼란스러웠을 것이 확실하다.
다른 곳에 있는 경우 코드가 불량 모델에 대한 유효한 패치일 수 있습니다(클래스는 장기간 유지되며 어떤 이유로 참조된 것은 오브젝트가 GC'd가 되기 전에 수동으로 해방되어야 합니다).일반적으로 듣는 사람을 지우는 것을 잊어버리고 왜 자신의 대상이 GC'd가 아닌지를 알 수 없기 때문에 언급하는 것을 지우고 어깨를 으쓱한 후 자리를 뜨게 됩니다.
"Quicker"를 청소하는 데 사용해서는 안 됩니다.
네가 이걸 어떻게 생각할 수 있을지 모르겠지만...
itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41
그래서 태양은 그것이 사용되어야 하는 몇 가지 사례를 발견했다고 생각합니다.
class MyObject {
Test main;
public MyObject(Test t) {
main = t;
}
protected void finalize() {
main.ref = this; // let instance become reachable again
System.out.println("This is finalize"); //test finalize run only once
}
}
class Test {
MyObject ref;
public static void main(String[] args) {
Test test = new Test();
test.ref = new MyObject(test);
test.ref = null; //MyObject become unreachable,finalize will be invoked
System.gc();
if (test.ref != null) System.out.println("MyObject still alive!");
}
}
====================================
결과:
This is finalize
MyObject still alive!
=====================================
따라서 도달 불능 인스턴스는 finalize 방식으로 도달할 수 있습니다.
finalize()
는 자원 누출을 포착하는 데 도움이 됩니다.리소스를 닫아야 하지만 닫히지 않은 사실을 로그 파일에 기록하고 닫지 않으면 리소스를 닫으십시오.이를 통해 리소스 누수를 제거하고 발생했음을 스스로 알 수 있으므로 문제를 해결할 수 있습니다.
1.0 alpha 3(1995)부터 자바에서 프로그래밍을 하고 있으며, 아직 어떤 것에 대해서도 finalize를 덮어쓰지 않았습니다.
리소스를 정리하기 위해 finalize()에 의존해서는 안 됩니다.finalize()는 클래스가 가비지 수집될 때까지 실행되지 않습니다.리소스를 사용한 후에는 리소스를 명시적으로 해방하는 것이 훨씬 좋습니다.
위의 답변 중 한 가지를 강조 표시하기 위해: 최종자는 단일 GC 스레드에서 실행됩니다.나는 개발자들이 몇몇 파이널라이저에 약간의 수면 시간을 더하고, 그렇지 않으면 일부러 멋진 3D 데모를 무릎 위에 올려놓는 주요 Sun 데모를 들어본 적이 있다.
피하는 것이 가장 좋습니다.단, 테스트 환경 진단은 예외입니다.
Eckel's Thinking in Java에는 이에 대한 좋은 섹션이 있습니다.
에서의 작업에 주의합니다.finalize()
특히 close()를 호출하여 리소스를 청소하는 등의 용도로 사용하는 경우에는 더욱 그렇습니다.실행 중인 Java 코드에 JNI 라이브러리가 링크되어 있는 몇 가지 상황이 발생하였습니다.또한 Finalize()를 사용하여 JNI 메서드를 호출하면 Java 힙 파손이 매우 심각해집니다.파손은 기본 JNI 코드 자체에 의한 것이 아니라 네이티브 라이브러리의 모든 메모리 트레이스에 문제가 없었습니다.finalize()에서 JNI 메서드를 호출하고 있다는 사실뿐입니다.
이것은 아직 널리 사용되고 있는 JDK 1.5를 사용한 것입니다.
문제가 발생한 것은 나중에야 알 수 있었습니다만, 결국 JNI 콜을 사용하는 finalize() 메서드가 원인입니다.
흠, 예전에 기존 수영장으로 돌려보내지 않은 물건들을 치우는 데 사용한 적이 있어요.
그들은 많이 돌아다녔기 때문에 언제 안전하게 수영장으로 돌아갈 수 있을지 알 수 없었다.문제는 가비지 수집 시 오브젝트를 풀링함으로써 절감되는 비용보다 훨씬 큰 막대한 패널티를 발생시켰다는 것입니다.약 한 달 동안 제작하다가 수영장 전체를 뜯어내고 모든 것을 역동적으로 만들어 완성했습니다.
리소스를 해방하기 위해 일종의 "정리" 메서드를 호출해야 하는 다른 개발자가 사용하는 코드를 작성할 때.경우에 따라서는 다른 개발자가 정리(또는 종료, 파기 등) 방법을 호출하는 것을 잊어버릴 수 있습니다.자원 누수가 발생하지 않도록 최종 메서드에서 메서드가 호출되었는지 확인하고 호출되지 않은 경우 직접 호출할 수 있습니다.
많은 데이터베이스 드라이버는 스테이트먼트와 Connection 구현에서 이를 통해 개발자가 가까운 곳에 전화하는 것을 잊어버리는 것을 방지하기 위해 약간의 안전성을 제공합니다.
편집: 네, 정말 안 돼요.가끔 실패해도 좋다고 생각했지만, 최종 방법이라고는 한 번도 부르지 않았습니다.
저는 전문 프로그래머는 아니지만, 제 프로그램에서 finalize()를 사용하는 좋은 사례로 생각되는 사례가 있습니다.이것은 파기되기 전에 디스크에 내용을 쓰는 캐시입니다.매번 파기할 필요는 없기 때문에 프로그램 속도만 빨라지기 때문에 잘못하지 않았기를 바랍니다.
@Override
public void finalize()
{
try {saveCache();} catch (Exception e) {e.printStackTrace();}
}
public void saveCache() throws FileNotFoundException, IOException
{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
out.writeObject(cache);
}
글로벌/스태틱 플레이스에 추가된 것을(필요에 따라) 제거할 수 있으며 오브젝트를 제거할 때 제거해야 합니다.예:
private void addGlobalClickListener() {weakAttEventListener = 새로운 취약점AWTEvent Listener(이것); Toolkit.get Default툴킷().addAWTEventListener(weakAwtEventListener, AWTEvent).마우스_EVENT_MASK); } @오버라이드protected void finalize() 슬로우 가능 {super.disc(); if(weakAttEventListener!= null) {Toolkit.get Default툴킷().삭제AWTEventListener(weakAwtEventListener); }}
승인된 답변 목록에는 최종 결정 중에 리소스를 닫을 수 있습니다.
그러나 이 답변은 적어도 JIT 컴파일러를 사용하는 Java8에서는 오브젝트에 의해 유지되는 스트림에서 읽기가 끝나기도 전에 파이널라이저가 호출되는 예기치 않은 문제가 발생했음을 나타냅니다.
따라서 이 경우에도 최종판정에 전화하는 것은 권장되지 않습니다.
iirc - 비용이 많이 드는 자원의 풀링 메커니즘을 구현하는 수단으로 finalize 방법을 사용할 수 있으므로 GC도 얻을 수 없습니다.
참고 사항으로:
finalize()를 덮어쓰는 개체는 가비지 컬렉터에 의해 특별히 처리됩니다.일반적으로 개체가 더 이상 범위를 벗어나면 수집 주기 동안 개체가 즉시 삭제됩니다.단, 완료 가능한 오브젝트는 큐로 이동합니다.이 큐에서는 다른 완료 스레드가 큐를 드레인하여 각 오브젝트에서 finalize() 메서드를 실행합니다.finalize() 메서드가 종료되면 오브젝트는 다음 사이클에서 최종적으로 가비지 수집 준비가 됩니다.
출처 : java-9에서는 finalize()가 폐지되었습니다.
리소스(파일, 소켓, 스트림 등)는 작업이 끝나면 닫아야 합니다.으로는 ★★★★★★★★★★★★★★★★★★★★★★★★.close()
으로는 「이러한 」이라고 .finally
의 try-catch
★★★★★★★★★★★★★★★★★★★★★.finalize()
또한 소수의 개발자에 의해 사용될 수 있지만 IMO는 적절한 방법이 아니다. 왜냐하면 최종판정이 항상 호출된다는 보장은 없기 때문이다.
Java 7 에서는, 다음과 같이 사용할 수 있는 try-with-resources 문이 있습니다.
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
// Processing and other logic here.
} catch (Exception e) {
// log exception
} finally {
// Just in case we need to do some stuff here.
}
의 예에서는 시 .BufferedReader
""를 close()
방법.필요에 따라서, Closeable을 독자적인 클래스에도 실장해, 같은 방법으로 사용할 수도 있습니다.IMO는 이해하기 쉽고 깔끔해 보인다.
사용하지 않았습니다.finalize()
, 경우 즉, ,, 음, 음, 음, 음, except, except, except, except, except, except, except, except, except, except의 경우를 제외하고는 제네릭 컬렉션을 커스텀을 .finalize()
다음과 같이 합니다.
public void finalize() throws Throwable {
super.finalize();
if (destructiveFinalize) {
T item;
for (int i = 0, l = length(); i < l; i++) {
item = get(i);
if (item == null) {
continue;
}
if (item instanceof Window) {
((Window) get(i)).dispose();
}
if (item instanceof CompleteObject) {
((CompleteObject) get(i)).finalize();
}
set(i, null);
}
}
}
)CompleteObject
실장되어 있지 않은 인터페이스를 것을 할 수 입니다.Object
「 」의 #finalize()
,#hashCode()
, , , , 입니다.#clone()
)
언니를 #setDestructivelyFinalizes(boolean)
method,은 이 하지 않게시킬 수 것을 수 .method, my collection은 My collection을 사용합니다.나도 어떤 스레드도 멈출까 생각했지만, 그것으로 완전히 새로운 웜의 통이 열렸다.
언급URL : https://stackoverflow.com/questions/158174/why-would-you-ever-implement-finalize
'source' 카테고리의 다른 글
Vuejs : vue-devtools에서 Vue 인스턴스의 이름을 지정할 수 있습니까? (0) | 2022.08.07 |
---|---|
vue 라우터 뷰에 데이터를 전달하는 방법 (0) | 2022.08.07 |
컨텐츠가 포함된 구성 요소를 Vue-grid-layout의 GridItem에 전달하는 방법은 무엇입니까? (0) | 2022.08.07 |
fcntl, lockf, 파일 잠금에 어떤 것을 사용하는 것이 좋습니까? (0) | 2022.08.07 |
Vue.js - 요소 UI - 양식 항목 레이블 슬롯 (0) | 2022.08.07 |