자바의 소멸자
•
자바에는 finalizer와 cleaner라는 두 가지 소멸자를 제공한다.
•
finalizer는 동작을 예측할 수 없고, 상황에 따라 위험할 수 있기 때문에 일반적으로 사용해서는 안된다.
•
cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 불필요하다.
finalizer와 cleaner의 문제점
•
finalizer와 cleaner는 메모리 수거 작업이 즉시 수행된다는 보장이 없다. 객체에 접근할 수 없게 된 이후, finalizer나 cleaner가 실행되기까지 얼마나 걸릴지 예측할 수 없다.
•
두 소멸자 모두 가비지 컬렉터의 알고리즘과 환경에 따라 동작이 다르기 때문에, 제때 실행되어야 하는 작업으로 finalizer와 cleaner를 수행하는 것은 불가능하다.
•
자바 언어 명세에는 finalizer와 cleaner의 수행 시점 뿐만아니라 수행 여부조차보장하지 않는다.
•
그렇기 때문에 상태를 영구적으로 수정하는 작업에서는 finalizer와 cleaner 모두 절대 의존해서는 안된다.
•
또한 두 소멸자는 심각한 성능 문제를 동반한다.
•
AutoCloseable 객체를 try-with-resources로 수거하면 12ns가 걸리는 작업을, finalizer를 호출하면 550ns가 걸린다.
•
finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 발생시킬 수 있다.
•
finalizer 공격은 생성자나 직렬화 과정에서 예외가 발생하면, 생성되다 실패한 객체에서 악의적인 하위 클래스의 finalizer가 수행될 수 있게 하는 것이다.
•
객체 생성을 막고자한다면 생성자에서 예외를 던지면 충분하지만, finalizer를 사용하면 finalizer 공격을 받을 수 있다.
•
final이 아닌 클래스를 finalizer 공격으로 방어하려면, finalize 메서드를 final로 선언하고 아무 것도 동작하지 않게 만들어 두어야 한다.
소멸자 사용 대안
•
객체의 클래스에서 종료해야할 자원이 있다면 AutoCloseable을 구현하고 close 메서드를 호출하자.
소멸자의 올바른 사용처
•
cleaner와 finalizer를 제대로 사용되는 경우로는, 자원의 소유자가 close 메서드를 호출하지 않을 경우에 대비하여 안전망 역할로 사용하는 것이다.
•
또 다른 경우로는, 네이티브 메서드를 통해 기능을 위임한 네이티브 객체(네이티브 피어)를 사용할 때이다. 네이티브 피어는 자바 객체가 아니므로 가비지 컬렉터가 인식할 수 없다.