이펙티브 자바:: 아이템 8 <finalizer와 cleaner 사용을 피하라>
🙈

이펙티브 자바:: 아이템 8 <finalizer와 cleaner 사용을 피하라>

Created
Aug 11, 2024 10:28 AM
Last edited time
Last updated August 22, 2024
Tags
Language
Language
Java
URL

Intro::

이펙티브 자바 정리본입니다.
 
결론부터 말하자면 finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요합니다. 또한 cleaner도 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요합니다.
 
finalizer와 cleaner는 C++에서의 파괴자와는 다른 개념입니다. C++에서는 파괴자에서 자원 회수를 하지만 자바는 가비지 컬렉터가 이를 담당하기 때문입니다. 자바에서는 try-with-resources와 try-finally를 사용해 해결합니다.
 

사용하면 안되는 이유

  1. finalizer와 cleaner는 즉시 수행된다는 보장이 없기 때문에, 제때 실행되어야 하는 작업을 절대할 수 없습니다.
  1. 자바 언어 명세는 finalizer와 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장하지 않습니다. 즉, 접근할 수 없는 일부 객체에 딸린 종료 작업을 전혀 수행하지 못한 채 프로그램이 중단될 수도 있다는 얘기입니다. 따라서 프로그램 생애주기와 상관없는, 상태를 영구적으로 수정하는 작업에서는 절대 finalizer와 cleaner에 의존해서는 안됩니다.
    1. 예시로 데이터베이스 같은 공유 자원의 영구 락 해제를 finalizer와 cleaner에 맡기면 분산 시스템 전체가 서서히 멈출것 입니다.
  1. finalizer와 cleaner는 심각한 성능 문제도 동반합니다.
    1. 안전망 방식에 비해 대단히 느립니다.
  1. finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있습니다.
    1. 생성자나 직렬화 과정에서 예외가 발생하면, 이 생성되다만 객체에서 악의적인 하위 클래스의 finalizer가 수행될 수 있게 됩니다.
    2. final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 아무 일도 하지 않는 finalize 메서드를 만들고 final로 선언합시다.
 

대안

  1. AutoCloseable을 구현해주고, 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출해주면 됩니다.
 

cleaner를 안전망으로 사용하는 AutoCloseable 클래스

public class Room implements AutoCloseable { private static final Cleaner cleaner = Cleaner.create(); // 청소가 필요한 자원. 절대 Room을 참조해서는 안 된다! private static class State implements Runnable { int numJunkPiles; // Number of junk piles in this room State(int numJunkPiles) { this.numJunkPiles = numJunkPiles; } // close 메서드나 cleaner가 호출한다. @Override public void run() { System.out.println("Cleaning room"); numJunkPiles = 0; } } // 방의 상태. cleanable과 공유한다. private final State state; // cleanable 객체. 수거 대상이 되면 방을 청소한다. private final Cleaner.Cleanable cleanable; public Room(int numJunkPiles) { state = new State(numJunkPiles); cleanable = cleaner.register(this, state); } @Override public void close() { cleanable.clean(); } }
// 잘 짜인 클라이언트 코드 public class Adult { public static void main(String[] args) { try (Room myRoom = new Room(7)) { System.out.println("안녕~"); } } }

질문

그럼 finalizer와 cleaner은 어디에 쓰는 건가??
  1. 자원의 소유자가 close 메서드를 호출하지 않는 것에 대한 안전망 역할
  1. 네이티브 피어와 연결된 객체 해제
 
 

References::

이펙티브 자바 / 조슈아 블로크 지음 (프로그래밍 인사이트)

Loading Comments...