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
보다는 더 나은 제어를 제공함