객체 생성과 파괴(Item 8)
Item 8. finalizer와 cleaner 사용을 피하라
어떤 객체를 사용하고 난 후에 사용된 자원을 닫아줘야 하는 경우가 있다.
파일을 다뤘거나 DB와 통신한 경우가 바로 그러한 경우다.
자바 8까지는 Finalizer
, 자바 9부터는 Cleaner
객체가 이 역할을 해주고 있다.
그러나, 이번 아이템에서는 두 객체를 사용하지 말라고 강하게 권고하고 있다.
Finalizer
Finalizer
를 사용하는 방법은 쉽다.
Object
클래스에 있는 finalize()
메서드를 재정의하여 자원을 해제하도록 하면 된다.
그러면 가비지 컬렉터(이하 GC)가 해당 객체를 제거할 때 finalize()
메서드를 호출한다.
다만, 이 방법은 절대 권장되지 않으며 자바 9부터는 Deprecated
되었고, 자바 18에서는 완전히 삭제되었다.
그렇다면 왜 Finalizer
를 사용하지 말라는걸까?
Finalizer의 단점
즉시 수행된다는 보장이 없다
기본적으로 GC가 동작해야 finalize()
메서드가 호출이 되는건데, 그 동작 시점을 예측할 수가 없다.
심지어 호출이 아예 안 될 수도 있다.
동작 중에 예외가 발생하면 정리 작업이 마무리 되지 못하고 종료될 수 있다
finalize()
메서드 실행 중에 예외가 발생하면 그 예외는 무시되며 그 즉시 종료된다.
이렇게 훼손된 객체를 사용하는 순간 어떤 일이 발생할지 모른다.
또한, 스레드를 중단시키고 예외 스택 추적 내역을 출력하지도 않는다.
성능이 구리다
Finalizer
는 GC의 효율을 떨어뜨려 성능을 저하시킨다.
Cleaner
자바 9에서부터 Finalizer
대신에 사용하라고 Cleaner
를 만들어 주었다.
Cleaner
객체는 Finalizer
보다는 그나마 낫다고 할 수 있지만 여전히 별로다.
Finalizer
와 마찬가지로 언제 실행될지 예측할 수 없으며 성능이 구리다.
대안
그렇다면 자원을 어떻게 닫으라는걸까?
가장 권장하는 자원 회수 방법은 AutoCloseable
인터페이스를 구현한 후에 try-with-resources
문법을 이용하는 것이다.
그러나 AutoCloseable
인터페이스를 구현했더라도 클라이언트가 try-with-resources
문법을 사용하지 않는다면 정상적으로 close()
메서드가 호출되지 않는다.
그러한 경우를 대비해 안전용으로 Cleaner
를 사용할 수는 있다.
객체 생성 시 Cleaner
에 해당 객체를 등록하면 자원이 회수될 일말의 여지는 있다.
클라이언트가 자원을 회수하지 않았으니 마지막 기회를 제공하는 셈이다.
이런 안전용으로서의 Cleaner
사용이 아니면 대체로 권장되지는 않는다.
[참고]
백기선, inflearn 강의 이펙티브 자바 완벽 공략 1부
Joshua Bloch, 이펙티브 자바