자바에서 두 가지 객체 소멸자인 finalizer과 cleaner를 제공한다. 하지만 이를 사용하는 것은 지양해야한다. 자바 9 에서 finalizer은 deprecated 되었고, clenaner가 대안으로 나왔으나 여전히 예측할 수 없고, 느리며, 불필요 하다.
public class FinalizerTest {
@Override
protected void finalize() throws Throwable {
System.out.println("Clean test");
}
public void test() {
System.out.println("test");
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
new Main().run();
Thread.sleep(100);
}
private void run() {
FinalizerTest finalizerTest = new FinalizerTest();
finalizerTest.test();
}
}
FinalizerTest의 인스턴스에 대한 GC(가비자 컬렉터)가 수행될때 "Clean test"라는 문자열을 출력되도록 finalize 메서드를 오버라이드 한 후 Main 클래스를 실행 해보자.
예상해 본다면 run 메서드가 종료되면 FinalizerTest의 인스턴스 참조가 존재하지 않기에 GC가 실행되어 0.1초 기다리는 사이에 "Clean test"가 출력되어야 한다.
하지만 실제 finalize 메서드는 호출되지 않는다.
자바 언어 명세는 어떤 스레드가 finalizer나 cleaner의 수행 시점뿐 아니라 수행 여부조차 보장하지 않는다.
그렇기에 상태를 영구적으로 수정하는 작업에서는 더욱이 finalizer나 cleaner의 사용을 지양하여야 한다.
cleaner나 finalizer가 즉시 호출되지 않을순 있지만, 클라이언트가 하지 않은 자원 회수를 늦게라도 해주는 것이 안전하다. 대표적으로 FileInputStrean, FileOupputStrea, ThreadPoolExecutor가 있다.
네이티브 객체는 일반적인 객체가 아니라서 GC가 그 존재를 모른다. 따라서 네이티브 피어가 들고 있는 리소스를 Cleaner나 Finalizer를 사용해서 해당 자원을 반납할 수도 있다.
하지만 이는 해당 자원이 중요하지 않거나, 성능상 영향이 크지 않다면 사용해야 한다.