Skip to content

item 8 dodo4513

황도영 edited this page Mar 28, 2020 · 1 revision

아이템8 finalizer와 cleaner 사용을 피하라

  • 자바는 두 가지 객체 소멸자를 제공한다. 그 중 finailzer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 그래서 자바 9에서는 finalizer를 사용 자제(deprecated) API로 지정하고 cleaner를 그 대안으로 소개했다(하지만 자바 라이브러리에서도 finalizer를 여전히 사용한다). cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다.

쓰면 안되는 이유!

  1. finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 객체에 접근할 수 없게 된 후 finalizer나 cleaner가 실행되기까지 얼마나 걸릴지 알 수 없다. 즉, finalizer와 cleaner로는 제때 실행되어야 하는 작업은 절대 할 수 없다. 한편, cleaner는 자신을 수행할 스레드를 제어할 수 있다는 면에서 조금 낫다. 하지만 여전히 백그라운드에서 수행되며 가비지 컬렉터의 통제하에 있으니 즉각 수행되리라는 보장은 없다.

  2. 자바 언어 명세는 finalizer나 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장하지 않는다. 따라서 프로그램 생애주기와 상관없는, 상태를 영구적으로 수정하는 작업에서는 절대 finalizer나 cleaner에 의존해서는 안 된다.

  3. finalizer 동작 중 발생한 예외는 무시되며, 처리할 작업이 남았더라도 그 순간 종료된다. 잡지 못한 예외 때문에 해당 객체는 자칫 마무리가 덜 된 상태로 남을 수 있다. 그리고 다른 스레드가 이처럼 훼손된 객체를 사용하려 한다면 어떻게 동작할지 예측할 수 없다.

  4. finalizer와 cleaner는 gc와 관련된 심각한 성능 문제도 동반한다.

  5. finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다. 객체 생성을 막으려면 생성자에서 예외를 던지는 것만으로 충분하지만, finalizer가 있다면 그렇지도 않다. 왜냐하면 생성자나 직렬화 과정에서 에러가 발생하면 생성되다 만 객체에 finalizer가 호출되고, 이 일그러진 객체를 이용해 원래는 호출할 수 없는 메서드들을 호출할 수 있게 된다.

자원의 해제는 그럼 어떻게 하는 것이 좋을까?

  • 그저 AutoCloseable을 구현해주고, 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출하면 된다.

핵심정리

cleaner(자바 8까지는 finalizer)는 안전망 역할이나 중요하지 않은 네이티브 자원 회수용으로만 사용하자.

물론 이런 경우라도 불확실성과 성능 저하에 주의해야 한다.

Clone this wiki locally