finalize ()를 명시 적으로 호출하거나 가비지 수집기를 시작하지 않는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/28949

  •  09-06-2019
  •  | 
  •  

문제

이 질문 을 읽은 후 Java와절대로 finalize ()를 호출하거나 가비지 수집기를 실행하지 말라고했습니다. "걱정할 필요가없는 큰 블랙 박스"이기 때문입니다.누군가가 이것에 대한 추론을 몇 문장으로 요약 할 수 있습니까?이 문제에 대해 썬의 기술 보고서를 읽을 수있을 것이라고 확신합니다.하지만 간단하고 짧고 멋진 답변이 제 호기심을 충족시킬 것이라고 생각합니다.

도움이 되었습니까?

해결책

짧은 대답 : Java 가비지 수집은 매우 미세 조정 된 도구입니다. System.gc ()는 큰 망치입니다.

Java의 힙은 여러 세대로 나뉘며 각 세대는 다른 전략을 사용하여 수집됩니다. 프로파일 러를 정상적인 앱에 연결하면 대부분의 개체가 젊은 세대의 더 빠른 복사 수집기에 포착되기 때문에 가장 비싼 종류의 컬렉션을 실행할 필요가 거의 없음을 알 수 있습니다.

System.gc ()를 직접 호출하면 기술적으로는 아무것도 할 수 없지만 실제로는 값 비싼 세계 중지 전체 힙 수집이 트리거됩니다. 이것은 거의 항상 잘못된 일입니다 . 리소스를 절약하고 있다고 생각하지만 실제로는 별다른 이유없이 리소스를 낭비하고 있으므로 Java가 "경우에 따라"모든 라이브 객체를 다시 확인해야합니다.

중요한 순간에 GC 일시 정지에 문제가있는 경우, 일시 정지에 소요되는 시간을 최소화하도록 특별히 설계된 동시 마크 / 스윕 수집기를 사용하도록 JVM을 구성하는 것이 좋습니다. 문제를 해결하고 더 나아가십시오.

생각했던 Sun 문서는 다음과 같습니다. Java SE 6 HotSpot ™ 가상 머신 가비지 수집 조정

(또 다른 사실 : 객체에 finalize () 메서드를 구현하면 가비지 수집 속도가 느려집니다. 첫째, 객체를 수집하는 데 2 GC 실행이 필요합니다. 하나는 finalize ( ) 및 다음을 사용하여 종료하는 동안 객체가 부활하지 않았는지 확인합니다. 둘째, finalize () 메서드가있는 객체는 개별적으로 수집해야하므로 GC에서 특수한 경우로 처리해야합니다. 대량으로.)

다른 팁

종료자를 신경 쓰지 마세요.

증분 가비지 수집으로 전환합니다.

가비지 수집기를 돕고 싶다면 더 이상 필요하지 않은 개체에 대한 참조를 null로 설정하세요. 따라갈 경로가 적습니다= 더 명시 적으로 쓰레기.

(비 정적) 내부 클래스 인스턴스는 부모 클래스 인스턴스에 대한 참조를 유지한다는 것을 잊지 마십시오. 따라서 내부 클래스 스레드는 예상보다 훨씬 많은 짐을 보관합니다.

매우 관련된 맥락에서 직렬화를 사용하고 임시 객체를 직렬화 한 경우 ObjectOutputStream.reset ()을 호출하여 직렬화 캐시를 지워야합니다. 그렇지 않으면 프로세스가 메모리를 누수하고 결국 죽습니다. 단점은 일시적이지 않은 개체가 다시 직렬화된다는 것입니다. 임시 결과 객체를 직렬화하는 것은 생각보다 더 복잡 할 수 있습니다!

소프트 참조 사용을 고려합니다. 소프트 참조가 무엇인지 모르는 경우 java.lang.ref.SoftReference 에 대한 javadoc을 읽어보십시오.

정말 흥분되지 않는 한 Phantom 참조와 Weak 참조를 피하세요.

마지막으로 GC를 참을 수 없다면 Realtime Java를 사용하세요.

아니요, 농담이 아닙니다.

참조 구현은 무료로 다운로드 할 수 있으며 SUN의 Peter Dibbles 책은 정말 읽기 좋습니다.

종료 자 기준 :

  1. 거의 쓸모가 없습니다.적시에 호출되거나 실제로는 전혀 호출되지 않는다는 보장이 없습니다 (GC가 실행되지 않으면 종료 자도 마찬가지입니다).이것은 일반적으로 그들에게 의존해서는 안된다는 것을 의미합니다.
  2. 종료자는 멱 등성을 보장하지 않습니다.가비지 수집기는 동일한 개체에서 한 번 이상 finalize()를 호출하지 않도록주의를 기울입니다.잘 작성된 객체의 경우 문제가되지 않지만 제대로 작성된 객체의 경우 finalize를 여러 번 호출하면 문제가 발생할 수 있습니다 (예 : 네이티브 리소스의 이중 릴리스 ... 충돌). finalize() 메서드가있는
  3. 모든 개체는 close() (또는 유사한) 메서드도 제공해야합니다.이것이 호출해야하는 함수입니다.예 : FileInputStream.close().사용자가 원하는 더 적절한 메소드가있는 경우 finalize()를 호출 할 이유가 없습니다.

종료자가 .NET 이름과 유사하다고 가정하면 누수 될 수있는 파일 핸들과 같은 리소스가있을 때만 호출하면됩니다.대부분의 경우 개체에는 이러한 참조가 없으므로 호출 할 필요가 없습니다.

정말 쓰레기가 아니기 때문에 수거하는 것은 나쁜 일입니다.개체를 만들 때 일부 메모리를 할당하도록 VM에 지시했으며 가비지 수집기가 해당 개체에 대한 정보를 숨기고 있습니다.내부적으로 GC는 메모리 할당에 대해 최적화를 수행합니다.수동으로 쓰레기를 모 으려고 할 때 GC가 무엇을 붙잡고 제거하고 싶은지 알지 못하며, 그저 손을 내밀면됩니다.결과적으로 내부 계산이 엉망이됩니다.

GC가 내부적으로 보유하고있는 내용에 대해 더 많이 알고 있다면 정보에 입각 한 결정을 내릴 수 있지만 GC의 이점을 놓친 것입니다.

Finalize에서 OS 핸들을 닫을 때 발생하는 실제 문제는 finalize가 보장 된 순서없이 실행된다는 것입니다. 그러나 차단하는 것 (예 : 소켓)에 대한 핸들이있는 경우 잠재적으로 코드가 교착 상태에 빠질 수 있습니다 (전혀 사소하지 않음).

그래서 저는 예측 가능한 순서대로 핸들을 명시 적으로 닫습니다. 기본적으로 리소스를 처리하는 코드는 다음 패턴을 따라야합니다. 라코 디스

JNI와 열린 핸들을 통해 작동하는 자체 클래스를 작성하면 훨씬 더 복잡해집니다. 핸들이 닫혀 있고 (풀림) 한 번만 발생하는지 확인해야합니다. Desktop J2SE에서 자주 간과되는 OS 핸들은 Graphics[2D]입니다. BufferedImage.getGrpahics()조차도 비디오 드라이버를 가리키는 핸들을 잠재적으로 반환 할 수 있습니다 (실제로 GPU에 리소스를 보유하고 있음). 직접 해제하지 않고 작업을 위해 가비지 수집기를 그대로두면 비디오 카드 매핑 된 비트 맵이 부족하지만 여전히 충분한 메모리가있을 때 이상한 OutOfMemory 및 유사한 상황을 발견 할 수 있습니다. 내 경험상 그래픽 객체 (썸네일 추출, 크기 조정, 이름을 선명하게하기)로 작업하는 타이트한 루프에서 자주 발생합니다.

기본적으로 GC는 올바른 리소스 관리에 대한 프로그래머의 책임을 돌보지 않습니다. 메모리 만 처리합니다. close () IMHO를 호출하는 Stream.finalize는 new RuntimeError ( "아직 열려있는 스트림을 수집하는 가비지") 예외를 던지고 더 잘 구현됩니다. 조잡한 아마추어가 끝을 잃은 후 코드를 디버깅하고 정리하는 데 몇 시간과 며칠을 절약 할 수 있습니다.

행복한 코딩입니다.

평화.

GC는 작업을 올바르게 마무리해야하는시기에 대해 많은 최적화를 수행합니다.

따라서 GC가 실제로 작동하는 방식과 생성에 태그를 지정하는 방식에 익숙하지 않은 경우 수동으로 finalize 또는 start GC를 호출하면 도움보다 성능이 저하 될 수 있습니다.

종료자를 피하십시오. 적시에 호출 될 것이라는 보장은 없습니다. 메모리 관리 시스템 (즉, 가비지 수집기)이 종료자를 사용하여 개체를 수집하기로 결정하는 데 시간이 오래 걸릴 수 있습니다.

많은 사람들이 종료자를 사용하여 소켓 연결을 닫거나 임시 파일을 삭제합니다. 그렇게함으로써 애플리케이션 동작을 예측할 수 없게 만들고 JVM이 개체를 GC 할 때 연결됩니다. 이로 인해 "메모리 부족"시나리오가 발생할 수 있습니다. Java 힙이 고갈되어서가 아니라 시스템이 특정 리소스에 대한 핸들이 부족하기 때문입니다.

또 하나 기억해야 할 점은 System.gc () 또는 그러한 망치에 대한 호출을 도입하면 사용자 환경에서 좋은 결과를 보여줄 수 있지만 반드시 다른 시스템으로 변환되는 것은 아닙니다. 모든 사람이 동일한 JVM을 실행하는 것은 아닙니다. SUN, IBM J9, BEA JRockit, Harmony, OpenJDK 등이 있습니다.이 JVM은 모두 JCK (공식적으로 테스트 된 것)를 준수하지만 일을 빠르게 만드는 데있어 자유. GC는 모든 사람이 많이 투자하는 영역 중 하나입니다. 망치를 사용하면 종종 그 노력이 파괴됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top