1 분 소요

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, 이펙티브 자바

<== Prev                                                   Next ==>