[아이템 8] finalizer와 cleaner 사용을 피하라
-
자바는 두 가지 객체 소멸자를 제공함
-
finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요함, 다양한 문제의 원인이 되어서 쓰임새가 있긴 하지만 기본적으로 안 씀
-
cleaner가 대안으로 나왔지만 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요함
-
그리고 이 2개는 즉시 수행된다는 보장이 없음, 얼마나 걸릴지 몰라서 제때 실행되어야 하는 작업은 절대 할 수 없음(파일 닫기와 같이)
-
이는 전적으로 가비지 컬렉터 알고리즘에 달려있어 천차만별임
-
클래스에 finalizer를 달아두면 그 인스턴스의 자원 회수가 제멋대로 지연될 수 있음 , 어떤 스레드가 finalizer를 수행할지 명시되어 있지 않아서
-
결국 finalizer나 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장을 못함, 접근할 수 없는 일부 객체에 딸린 종료 작업을 전혀 수행하지 못한 채 프로그램이 중단될 수 있는 것, 상태를 영구적으로 수정하는 작업에서는 finalizer나 cleaner에 의존해서는 안됨(데이터베이스 같은 공유 자원의 영구 락 해제등)
-
System.gc
,System.runFinalization
메서드가 있지만, 실행될 가능성을 높여줄 수 있으나 보장해주진 않음, 이를 보장해주는 메서드조차도 심각한 결함이 있음 -
finalizer동작 중 발생한 예외는 무시되며, 처리할 작업이 남았더라도 그 순간 종료됨, 잡지 못한 예외때문에 해당 객체는 자칫 마무리가 덜 된 상태로 남을 수 있음, 그리고 이런 훼손된 객체를 사용하려면 어떻게 동작할지 예측할 수 없음(Cleaner의 경우 스레드를 통제해서 이런 문제는 발생하지 않음)
-
finalizer와 cleaner는 심각한 성능 문제도 동반함, 가비지 컬렉터의 효율을 떨어뜨림
-
finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수 있음, 생성자나 직렬화 과정에서 예외가 발생하며나, 이 생성되다 만 객체에서 악의적인 하위 클래스의 finalizer가 수행될 수 있게 됨, 그리고 정적 필드에 자신의 참조를 할당해 가비지 컬렉터가 수집하지 못하게 막을 수 있음
-
이렇게 일그러진 객체가 만들어지면 이 객체의 메서드를 호출해 애초에 허용되지 않았을 작업을 수행할 수 있음
-
객체 생성을 막으려면 생성자에서 예외를 던지는 것만으로 충분하지만, finalizer가 있다면 그렇지도 않음, final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 아무 일도 하지 않는 finalize 메서드를 만들고 final로 선언해야함
-
이런 finalizer나 cleaner를 대신해줄 묘안은 AutoCloseable을 구현해주고, 클라이언트에서 인스턴스를 다 쓰고 나면 close 메서드를 호출하면 됨
-
close 메서드에서 이 객체는 더 이상 유효하지 않음을 필드에 기록하고, 다른 메서드는 이 필드를 검사해서 객체가 닫힌 후에 불렸다면 IllegalStateException을 던지는 것임
AutoCloseable?
이 AutoCloseable은 close 메서드를 통해서 close 처리를 자동으로 처리해주는 것임
기존에 자원을 해제하는 방식은 try-catch-finally 방식이었고 여기서 좀 더 향상된 방식인 try-with-resources를 통해서 try를 벗어나면 try 안에 선언된 객체의 close 메서드를 호출해 close한 상황을 명시할 수 없게 되었는데 하지만 그렇다고 무조건 모든 객체를 close 해주지 않음
그래서 AutoCloseable을 구현한 객체를 통해서 close 메서드를 통해서 자원을 처리할 수 있는 것임
아래와 같이 구현을 함으로써 알아서 close가 호출이 되는 것임
public class AutoCloseableExample {
public static void main(String[] args) {
try (CustomResource customResource = new CustomResource()){
customResource.doSomething();
} catch (Exception e){
e.printStackTrace();
}
}
}
public class CustomResource implements AutoCloseable {
public void doSomething(){
System.out.println("Do something ...");
}
@Override
public void close() throws Exception {
System.out.println("CustomResource Closed!");
}
}
-
그렇다면 이 finalizer와 cleaner에 쓰임새가 없는 것인가 생각할 수 있지만 그래도 어느정도의 쓰임새는 존재함
-
먼저 자원의 소유자가 close 메서드를 호출하지 않는 것에 대비한 안전망 역할임, finalizer나 cleaner가 즉시 호출되리라는 보장은 없지만, 클라이언트가 하지 않은 자원 회수를 늦더라도 해주는 것이 아예 안 하는 것보다 나음(대신 그런 값어치가 있는지 잘 생각해야함)
-
그러고 두 번째로는 네이티브 피어임, 네이티브 피어란 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체를 말함
-
네이티브 피어는 자바 객체가 아니니 가비지 컬렉터는 그 존재를 알지 못함, 그 결과 자바 피어를 회수할 때 네이티브 객체까지 회수하지 못함, 이때 finalizer나 cleaner가 나서서 처리를 함
-
단, 성능 저하를 감당할 수 있고, 네이티브 피어가 심각한 자원을 가지고 있지 않을 때에만 해당함, 성능 저하를 감당할 수 없거나 네이티브 피어가 사용하는 자원을 즉시 회수해야 한다면 close 메서드를 사용해야함
네이티브 피어?
네이티브 피어
네이티브 피어란 자바로 만든 것이 아닌 C,C++같은 언어로 작성된 것을 의미함, 그래서 네이티브 메서드는 이런 언어로 작성한 메서드고 네이티브 피어는 이런 상황에서 자바 객체가 네이티브 메서드를 통해 기능 수행을 위임한 상황을 말함
그래서 이 상황에서 메모리 할당과 가비지 컬렉터에서 처리를 하지 못함, 네이티브 메서드로 위임되면서 자원의 반납 여부를 알 수 없기 때문임
그래서 이런 경우 finalizer나 cleaner를 통해 객체 소멸을 할 수 있다고 한 것임
Author And Source
이 문제에 관하여([아이템 8] finalizer와 cleaner 사용을 피하라), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gang_shik/아이템-8-finalizer와-cleaner-사용을-피하라저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)