아이템 8 : finalizer와 cleaner 사용을 피하라
자바는 두 가지 객체 소멸자를 제공한다. 그중 finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다.
cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다.
finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 객체에 접근 할 수 없게 된 후 finalizer와 cleaner가 실행되기까지 얼마나 걸릴지 알 수 없다. 즉, finalizer와 cleaner로는 제때 실행되어야 하는 작업은 절대 할 수 없다.
자바 언어 명세는 finalizer나 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장하지 않는다. 접근할 수 없는 일부 객체에 딸린 종료 작업을 전혀 수행하지 못한 채 프로그램이 중단될 수도 있다는 이야기다. 따라서 프로그램 생애주기와 상관없는, 상태를 영구적으로 수정하는 작업에서는 절대 finalizer나 cleaner에 의존해서는 안 된다.
finalizer와 cleaner는 심각한 성능 문제도 동반한다.
finalizer와 cleaner가 가비지 컬렉터의 효율을 떨어뜨리기 때문이다.
finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다.
finalizer 공격 원리는 생성자나 직렬화 과정에서 예외가 발생하면, 이 생성되다 만 객체에서 악의적으로 하위 클래스의 finalizer가 수행되게 하는 것이다. 이 finalizer는 정적 필드에 자신의 참조를 할당하여 가비지 컬렉터가 수집하지 못하게 막을 수 있다.
객체 생성을 막으려면 생성자에서 예외를 던지는 것만으로 충분하지만, finalizer가 있다면 그렇지도 않다.
final 클래스들은 그 누구도 하위 클래스를 만들 수 없으니 이 공격에서 안전하다. final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 아무 일도 하지 않는 finalize 메서드를 만들고 final로 선언하자.
핵심 정리
cleaner는 안전망 역할이나 중요하지 않은 네이티브 자원 회수용으로만 사용하자. 물론 이런 경우라도 불확실성과 성능 저하에 주의해야 한다.
'언어 > JAVA' 카테고리의 다른 글
[Effective Java] equals는 일반 규약을 지켜 재정의하라 (0) | 2020.03.13 |
---|---|
[Effective Java] try-finally보다는 try-with-resources를 사용하라 (0) | 2020.03.13 |
[Effective Java] 다 쓴 객체 참조를 해제하라 (0) | 2020.03.12 |
[Effective Java] 불필요한 객체 생성을 피하라 (0) | 2020.03.11 |
[Effective Java] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2020.03.11 |