1 minute read

item8 finalizercleaner 사용을 피하라.

  • finalizer : 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요
  • cleaner : finalizer보다 덜 위험하지만, 여전히 예측할 수 없고, 느리고 일반적으로 불필요
  1. 두 객체 소멸자 모두 GC의 대상은 되지만, 즉시 수행된다는 보장이 없다.
  • File I/O를 두 객체 소멸자에 맡기면, 시스템이 동시에 열 수 있는 파일 개수에 한계가 있으므로 반납이 되지 않는 현상으로 새로운 파일을 열지 못하게 되므로 중대한 오류를 일으킬 수 있다.
  1. 두 객체 소멸자 모두 수행 여부에 대한 보장이 없다.
  • DB와 같은 공유 자원의 영구 락 해제를 두 객체 소멸자에 맡긴다면 시스템 전체가 서서히 멈추게 될 것이다.
  1. finalizer 동작 중 발생한 예외는 무시되며, 처리할 작업이 남아있더라도 그 순간 종료된다. 잡지 못한 예외 때문에 객체가 마무리가 덜 된 상태로 남을 수 있다.

  2. 두 객체 소멸자는 성능 문제도 동반한다.

  • AutoCloseable 객체를 사용해 처리할 때보다 50배 이상 느리다.
  1. finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다.
  • 생성이나 직렬화 과정에서 예외가 발생하면, 생성되다 만 객체에서 악의적인 하위 클래스의 finalizer가 수행될 수 있게 된다.
  • AutoCloseable을 구현하고 클라이언트에서 인스턴스를 다 쓰고나면 close 메서드를 호출하자.
    • try-with-resourse를 사용하여 자원을 종료하자.

finalizercleaner 사용 이유

  1. 자원 소유자가 close 호출하지 않는 것에 대한 대비
  2. 네이티브 피어 관련 객체 회수
    • 네이티브 피어는 자바 객체가 아니므로 GC에서 회수 불가능

public class Room implements AutoCloseable {  
  
    private static final Cleaner cleaner = Cleaner.create();  
  
    private static class State implements Runnable {  
        int numJunkpiles;  
  
        State(int numJunkpiles) {  
            this.numJunkpiles = numJunkpiles;  
        }  
		
		// close 메소드나 cleaner 호출
        @Override  
        public void run() {  
            System.out.println("방 청소");  
            numJunkpiles = 0;  
        }  
    }  
    
    private final State state;  
    // 수거 대상이 되면 방을 청소
    private final Cleaner.Cleanable cleanable;  
  
    public Room(int numJunkpiles) {  
        state = new State(numJunkpiles);  
        cleanable = cleaner.register(this, state);  
    }  
  
    @Override  
    public void close() throws Exception {  
        cleanable.clean();  
    }  
}

// 클라이언트가 try-with-resources 블록으로 감쌌다면 방 청소를 정상적으로 출력한다.
public class Adult {  
  public static void main(String[] args) throws Exception {  
		try (Room myRoom = new Room(7)) {
			System.out.println("안녕~");
		}
		new Room(99);
		System.out.println("아무렴~");
  }
}

// 청소가 항상 보장되지 않는다.
public class Teenager {  
  public static void main(String[] args) throws Exception {  
		new Room(99);
		System.out.println("아무렴~");
  }
}


Leave a comment