finalize() 메서드는 Object 클래스에서 정의된 메서드
가비지 컬렉터가 객체를 메모리에서 회수하기 전에 호출됩니다. 이 메서드는 자바에서 객체가 소멸될 때 필요한 정리 작업을 수행하기 위해 사용
사용방법
finalize() 메서드를 자신의 클래스에서 오버라이드하여 객체가 소멸될 때 실행할 코드를 정의public class ExampleClass {
@Override
protected void finalize() throws Throwable {
// 정리 코드 실행
System.out.println("Finalizing an instance of ExampleClass.");
super.finalize();
}
}
Java 9 이후로 도입된 java.lang.ref.Cleaner 클래스를 활용하는 메커니즘으로, finalize() 메서드의 대안으로 제안되었음
이는 finalize()가 가진 성능 문제와 예측 불가능성을 해결하고, 객체 리소스의 안정적이고 명시적인 정리를 가능하게 해줌
사용 방법
Cleaner 객체를 생성하고, 이를 통해 정리하고자 하는 객체와 연결된 정리 작업을 등록Cleaner에 등록하고, 등록된 작업은 Cleanable 인스턴스로 관리됨. 등록 시 정리 대상 객체와 정리 작업을 제공import java.lang.ref.Cleaner;
public class Resource implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
public Resource() {
this.cleanable = cleaner.register(this, () -> {
// 여기에 정리 코드를 작성합니다.
System.out.println("Cleaning up resource.");
});
}
@Override
public void close() {
cleanable.clean();
}
}
public class Main {
public static void main(String[] args) {
try (Resource res = new Resource()) {
// 리소스를 사용하는 로직
} // 자동으로 close 메소드 호출, 여기서 정의된 Cleaner 작업 실행
}
}
finalizer나 cleaner는 객체가 더 이상 사용되지 않을 때 실행되지만, 그 시점이 언제일지 예측할 수 없음
왜??
finalizer나 cleaner의 실행 시점은 전적으로 가비지 컬렉터의 알고리즘에 따라 결정되기 때문!즉, 시간에 민감한 작업(예: 파일 닫기)은 finalizer나 cleaner로 처리하면 안 됨
finalizer나 cleaner에 맡기면 파일이 너무 오래 열려 있는 상태가 유지될 수 있음실제 문제 발생 사례
OutOfMemoryError로 종료된 사례가 있었는데, 이때 수천 개의 그래픽 객체가 finalizer 대기열에서 회수되기를 기다리고 있었음finalizer 스레드는 우선 순위가 낮아서 제때 실행되지 않았고, 결과적으로 시스템에 치명적인 영향을 미쳤음최선의 방법: finalizer를 사용하지 않는 것이 가장 확실한 예방책
Cleaner의 경우:
cleaner는 백그라운드에서 실행되지만, 그래도 자신만의 스레드를 사용해 finalizer보다는 더 나은 제어를 제공함