[이펙티브 자바] 아이템8

hyng·2022년 11월 25일
0

이펙티브 자바

목록 보기
8/13

finalizer와 cleaner 사용을 피하라

finalizer와 cleaner

자바는 객체 소멸자로 finalizer와 cleaner를 제공한다. 자바 9에서는 finalizer를 deprecated API로 지정하고 cleaner를 대안으로 소개했지만 cleaner도 사용하지 않는 것이 좋다.

소멸자는 객체가 GC에 의해 제거될 때 호출된다.

그럼 왜 사용하지 말라고 하는 것일까?

즉시 수행된다는 보장이 없다.

만약 파일 닫기가 제때 되지 않아 파일을 계속 열어둔다면 새로운 파일을 열지 못해 프로그램이 실패할 수 있다.

수행 시점뿐만 아니라 수행 여부조차 보장하지 않는다.

예를 들어 데이터베이스 같은 공유 자원의 락 해제를 finalizer나 cleaner에 맡겨놓으면 분산 시스템 전체가 서서히 멈출 것이다.
finalizer나 cleaner를 얼마나 신속히 수행할 지는 전적으로 가비지 컬렉터 알고리즘에 달렸으며, 이는 가비지 컬렉터 구현마다 다르다.

finalizer 동작 중 발생한 예외는 무시되며, 처리할 작업이 남았더라도 그 순간 종료된다.

예외가 발생하여 마무리가 덜 된 객체를 다른 스레드에서 접근하게 될 수도 있다. cleaner를 사용하는 라이브러리는 자신의 스레드를 통제하기 때문에 이러한 문제가 발생하진 않는다.

finalizer와 cleaner는 심각한 성능 문제도 동반한다.

  • AutoCloseable 객체 생성 try-with-resources로 닫도록 함 -> 12ns
  • finalizer 사용 -> 550ns
  • cleaner 사용 -> 500ns

finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있다.

  • 생성자에 검증 로직을 두고 검증 실패 시 예외를 던지는 코드가 있다고 할 때, 예외가 발생하여 후에 finalize() 메서드가 호출된다고 가정해 보자.
    이때 finalize() 메서드에서는 내부 static 필드에 자기 자신에 대한 참조를 저장하는 코드가 있다. 그럼 결과적으로 이 객체는 static 필드로 인해 참조되고 있는 상태이기 때문에 gc 대상이 되지 못하고 분명 검증에 실패했지만 객체가 생성된 상태가 된다.
  • 이외에도 상위 클래스를 상속받은 하위 클래스를 만들고 이 하위 클래스에 finalize() 메서드를 오버라이딩해서 static 필드에 자신 자신에 대한 참조를 저장하도록 할 수도 있다.
  • finalizer를 사용할 때 이런 보안 문제를 해결하기 위해서 클래스에 final을 붙여서 상위 클래스를 상속한 하위 클래스를 만들지 못하게 하거나 아무 일도 하지 않는 finalize() 메서드를 만들고 final로 선언하는 방법이 있다.
  • 책 내용만으로 이해가 되지 않아 찾아 본 내용 -> 참고

그럼 어떤 방법을 사용해야 할까?

AutoCloseable 을 구현하고 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출하는 것이다. (예외가 발생되어도 제대로 종료되도록 try-with-resources를 사용하는 것이 좋다.) 그리고 각 인스턴스는 자신이 닫혀있는지를 추적하는 것이 좋다. 객체가 더 이상 유효하지 않음을 필드에 기록하고 close 메서드에서 필드 값을 확인해 객체가 닫힌 후라면 IllegalStateException을 던지는 것이다.

finalizer와 cleaner는 어디에 쓰는 걸까?

  1. 안전망 역할
    자원의 소유주가 close 메서드를 호출하지 않는 것에 대비한 안전망 역할이다. 호출되리라는 보장은 없지만 클라이언트가 하지 않은 자원 회수를 늦게라도 해주는 것이 아예 안 하는 것보다는 낫다.

  2. 네이티브 피어
    네이티브 피어는 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체를 말한다. 네이티브 피어는 자바 객체가 아니니 gc 대상이 되지 못한다.
    성능 저하를 감당할 수 없거나 즉시 반환해야 하는 자원이라면 close 메서드를 사용해야 한다.

profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글