📖본 포스팅은 'Effective java - 조슈아' 님의 책를 보고 작성되었습니다.
[객체 소멸자 - finalizer / cleaner ]
[finalizer]
- 예측할 수 없고 상황에 따라 위험할 수 있어 일반적으로 불필요하다.
- 오동작, 낮은 성능, 이식성 문제의 원인이 된다.
- deprecated API로 지정되어 있기에 사용하지 않을 것을 권장한다.
[cleaner]
- finalizer의 대안책으로 나왔지만 이 역시도 문제가 많다.
- finalizer보다는 덜 위험하지만, 여전히 예측 불가하고, 느리고, 일반적으로 불필요하다.
[C++의 파괴자]
- C++의 파괴자는 비메모리를 회수하는 용도로 쓰인다.
- 특정 객체와 관련된 자원을 회수하는 보편적인 방법이 C++의 파괴자이다.
- 자바는 객체 회수의 역할은 가비지 컬렉터가 담당해 프로그래머는 아무런 작업을 하지 않아도 된다.
- c++의 파괴자는 다른 개념으로 자바에서는 try-with-resources와 try-finally를 사용해서 해결한다.
[객체 소멸자 - finalizer /cleaner의 문제점]
[제때 실행되어야 하는 작업에서 사용할 수 없는 객체 소멸자 - finalizer / cleaner]
- 즉시 수행된다는 보장이 둘 다 없으며 객체에 접근할 수 없게 된 후 객체 소멸자가 실행되기까지 얼마나 걸릴지 알 수가 없다.
- 즉, 제때 실행되어 객체를 소멸시켜야 하는 작업에서는 이를 절대 사용하면 안된다.
- 예를 들어 파일 닫기를 - finalizer / cleane에게 맡긴다면 중대한 오류를 낼 수 있다. 왜냐하면 시스템은 동시에 열 수 있느 파일 개수에 한계가 있기 때문이다.
[수행 시점뿐만 아니라 수행 여부조차 보장하지 않는 객체 소멸자 finalizer / cleaner]
- 접근할 수 없는 일부 객체에 딸린 종료 작업을 전혀 수행하지 못한 채 프로그램이 중단될 수도 있다는 이야기다.
- 생애주기와 상관 없는 상태를 영구적으로 수정하는 작업에서는 finalizer / cleaner에 의존해서는 안 된다.
- 예를 들어 데이터베이스 같은 공유 자원의 영구 락(Lock) 해제를 finalizer / cleaner에 맡겨 놓으면 분산 시스템 전체가 서서히 멈추게 될 것이다.
[finalizer / cleaner의 실행 가능성을 높여주는 메서드에 현혹되지 말자]
- System.gc나 System.runFinalization 메서드는 가능성을 높여주는 것이지 보장하지 않는다.
- System.runFinalizersOnExit와 Runtime.runFinalizersOnExit는 실행 가능성을 보장하지만 심각한 결함이 있어서 많은 잡음이 있다.
[처리할 작업이 남아도 발생한 예외에 종료되는 - finalizer]
- 처리할 작업이 남아있어도 예외가 발생하면 종료되는 finalizer 때문에 해당 객체는 마무리가 덜 된 상태로 남아있을 수 있다.
- 또한 이 훼손된 객체를 다른 쓰레드가 사용하려한다면 어떻게 동작할지 예측할 수 없다.
- 이런 경우 보통 경우라면 잡지 못한 예외가 스레드를 중단시키고 스택 추적 내역을 출력하지만 finalizer에서 일어난 일이라면 경고조차 출력하지 않는다.
- 그래도 cleaner를 사용하는 라이브러리는 자신의 스레드를 통제하기에 이런 문제는 발생하지 않는다.
[finalizer / cleaner의 심각한 성능 문제]
- 객체 파괴할 때 시간이 매우 오래 걸린다.
[finalizer 사용할 때 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있다.]
[이 쓸모 없는 finalizer / cleaner의 쓰임새]
- 자원 소유자가 close 메서드를 호출하지 않은 것에 대비한 안전망 역할
- 이는 즉시 호출되지 않는 애들이라도 하지 않는 것보단 낫기 때문에 자원 회수를 늦게라도 하게 하기 위해서 사용할 때가 있다.
- 네이티브 피어(native peer)와 연결된 객체에서의 사용
- 네이티브 피어란 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체를 말한다.
- 네이티브 객체는 자바 가비지 컬렉터에서 존재를 알 수 없기에 이를 회수할 수 없어 이때 finalizer cleaner이 나서서 처리해준다.
- 네이티브 피어가 사용하는 자원을 즉시 회수해야 한다면 close 메서드를 사용해야 한다.
[핵심 정리]
cleaner은 안전망 역할일 뿐 중요하지 않은 네이티브 자원 회수용으로만 사용해야 한다. 물론 이런 경우도 불확실성과 성능 저하에 주의하며 사용해야 한다.
'Java > 이펙티브 자바(Effective Java)' 카테고리의 다른 글
[이펙티브 자바(Effective Java)] - 3장 모든 객체의 공통 메서드 (0) | 2022.04.12 |
---|---|
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 9. try-finally보다는 try-with-resources를 사용하라 (0) | 2022.04.11 |
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 7. 다 쓴 객체 참조를 해제하라 (0) | 2022.04.11 |
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 6.불필요한 객체 생성을 피하라 (0) | 2022.04.08 |
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.04.08 |