[Effective Java 뽀개기] 08. finalizer와 cleaner 사용을 피하라



image-20220904212556629

자바는 두가지 객체 소멸자를 제공하는데 그중 finalizer 는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다.

→ 자바 9에서는 deprecated 되었고, cleaner 를 대안으로 소개했지만.. 얘도 사실 똑같다..

자바의 finalizercleaner는 C++의 파괴자(destructor)와는 다른 개념이다.

  • C++에서의 파괴자
    • 생성자의 꼭 필요한 대척점으로 특정 객체와 관련된 자원을 회수하는 보편적인 방법
    • 비메모리 자원을 회수하는 용도
  • Java에서의 finalizer와 cleaner
    • 즉시 수행된다는 보장이 없어, 제때 실행되어야 하는 작업은 절대 할 수 없다.(수행 시점 보장 X)
      • 자원 회수가 제멋대로 지연될 수 있다.
      • 해당 로직을 얼마나 신속히 수행할지는 전적으로 가비지 컬렉터 알고리즘에 달렸다.
    • 제대로 수행된다는 보장이 없다. (수행 여부 보장 X)
      • 제대로 수행되지 못한채 프로그램이 중단될 수도 있다.

상태를 영구적으로 수정하는 작업에서는 절대 finalizercleaner 에 의존해선 안된다.

→ (ex) 데이터베이스의 영구 락 해제를 얘네한테 맡겨놓으면 분산 시스템 전체가 서서히 멈출것이다…

또한 해당 소멸자를 보장해 준다는 모든 것을 믿지 말자. (보장해 준다는 메서드가 있었지만 심각한 결함때문에 수십년간 욕먹었다.)


finalizer를 더 까봅시다.

1. 동작 예측 불가

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

잡지못한 예외때문에 해당 객체는 마무리가 덜 된 상태로 남을 수 있으며, 다른 스레드가 훼손된 해당 객체를 사용하려 한다면 어떻게 동작할지 예측할 수 없다.

보통의 경우엔 잡지 못한 예외가 스레드를 중단시키고 stack trace를 출력하겠지만, 해당 일이 finalizer에서 일어난다면 경고조차 출력하지 않는다. (그나마 cleaner는 자신의 스레드를 통제하기 때문에 이런 문제는 없다.)


2. 심각한 성능 문제

finalizer 가 가비지 컬렉터의 효율을 떨어뜨린다. (저자의 테스트로는 가비지 컬렉터보다 50배 느렸음)


3. 심각한 보안 문제

finalizer 공격에 노출되어 심각한 보안 문제가 일어날 수 있다.

→ 해당 공격은 생성자나 직렬화 과정에서 예외가 발생시 훼손된 객체에서 악위적인 하위 클래스의 finalizer가 수행될 수 있다.

final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 아무일도 하지 않는 finalize 메서드를 만들고 final로 선언하라.

종료해야 할 자원을 담고있는 객체의 클래스에서 위 두 친구 대신 AutoCloseable 을 구현해주고, 인스턴스를 다 쓰고나면 close 메서드를 호출하도록 한다. (try-with-resources를 사용하는 방법이 best)


저 두놈은 어디에 쓰는걸까

1. 자원의 소유자가 close 메서드를 호출하지 않는것에 대비한 안전망 역할

즉시 혹은 끝까지 호출되리라는 보장은 없지만 아예 안하는것보다는 낫기 때문이다.

(ex) FileInputStream, FileOutputStrema, ThreadPoolExecutor


2. 네이티브 피어(native peer)와 연결된 객체

네이티브 피어란 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체이다.

네이티브 피어는 자바객체가 아니라 가비지 컬렉터는 그 존재를 알지 못하고, 결국 회수하지 못한다. 이 경우 저 두 친구를 사용한다.

→ 대신, 성능 저하를 감당할 수 있고 네이티브 피어가 심각한 자원을 가지고 있지 않을 때에만 해당된다. 그냥 close 메서드를 사용하자…

(이후에 책 내에서 cleaner의 사용방법에 대한 내용이 있는데.. 굳이 필사할 정도는 아닌것 같아 pass함)


정리

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

물론 불확실성과 성능 저하에 주의해야한다.




© 2019. by mintheon

Powered by mintheon