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

2021. 6. 26. 18:33책/이펙티브자바

자바에서는 두 가지 객체 소멸 자를 제공한다.

finalizer

  • 오동작, 낮은 성능
  • 예측할 수 없고 위험하여 일반적으로 불필요하다.
  • 자신을 수행할 스레드를 제어할 수 없다.
  • finalizer 공격에 노출되어 심각한 보안문제를 일으킬 수 있다.
    • 생성자나 직렬화 과정에서 예외가 발생하면, 악의적으로 하위 클래스의 finalizer가 수행될 수도 있다.
      • GC가 수집하지 못하게 막을 수 있다.
  • 위와 같은 이유로 Java9 에서 deprecated 되었고 새로운 대안으로 cleaner를 소개한다.

cleaner

  • finalizer 보다는 덜 위험하다.
  • 하지만 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다.
  • 자신을 수행할 스레드를 제어할 수 있다.

공통사항

  • 즉시 수행된다는 보장이 없다.
  • 실행되기까지 얼마나 걸릴지 알 수 가없다.
  • 제때 실행되어야 하는 작업은 절대 할 수 없다.
  • 심각한 성능문제를 동반한다.
  • 얼마나 신속히 수행할지는 전적으로 GC 알고리즘에 달렸다.

그러면 finalizer 와 cleaner는 어디에 쓰이는가 ?

  • 자원의 소유자가 close 메서드를 호출하지 않는 것에 대비한 안전망 역할
    • 즉시 수행한다는 보장은 없지만 아예 안하는 것보다는 낫다.
    • 라이브러리의 일부 클래스는 안전망 역할의 finalizer를 제공한다.
      • ex) FileInputStream, FileOutputStream, ThreadPoolExcecutor
  • 네이티브 피어 (native peer)와 연결된 객체
    • 네이티브 피어 ?
      • 일반 자바 객체가 네이티브 메서드를 통해서 기능을 위임한 네이티브 객체
    • GC 가 자바객체가 아니니 존재를 알지 못한다.
      • 회수하지 못함
      • finalizer나 cleaner 가 나서서 처리하기에 적당한 작업
    • 단, 성능 저하를 감당할 수 있고 네이티브 피어가 심각한 자원을 가지고 있지 않을 때에만 해당된다.

대안

그러면 파일이나 스레드 등 종료해야 할 자원을 담고 있는 객체의 클래스에서 어떻게 해야할까 ?

  • AutoCloseable을 구현하고 클라이언트에서 인스턴스를 다 쓰고 나면 close 메소드를 호출하면 된다.
  • (일반적으로 예외가 발생해도 제대로 종료되도록 try-with-resource 사용이 권장된다.)

결론

cleaner는 안전망 역할이나 중요하지 않은 네이티브 자원 회수용으로만 사용한다.

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