Effective Java 3/E 판을 읽고 정리한 기록입니다.
finalizer와 cleaner는 객체가 더 이상 필요하지 않을 때 정리 작업을 수행할 수 있는 방법을 제공합니다.
하지만 이들은 성능, 안정성, 예측 가능성 등의 측면에서 여러 문제를 일으킬 수 있어 주의해야합니다.
Finalizer란 무엇인가?
finalizer는 Java에서 객체가 가비지 컬렉션에 의해 회수될 때 호출되는 메서드입니다.
Object 클래스의 finalize 메서드를 오버라이드해 정의할 수 있습니다.
class Resource {
@Override
protected void finalize() throws Throwable {
try {
// 리소스 해제 코드
System.out.println("Resource finalized");
} finally {
super.finalize();
}
}
}
문제점
예측 불가능한 실행 시점
finalize 메서드는 가비지 컬렉터에 의해 호출되므로,
정확히 언제 호출될지 예측할 수 없습니다.
이는 리소스 해제를 지연시키거나 전혀 발생하지 않게 만들 수 있습니다.
성능 저하
finalizer의 사용은 가비지 컬렉션의 성능을 저하시킬 수 있습니다.
가비지 컬렉션 시에 추가적인 처리 비용이 발생하기 때문입니다.
오류 회피의 어려움
finalizer 내에서 발생한 예외는 무시되며,
가비지 컬렉터는 이를 다시 시도하지 않습니다. 따라서, 오류 처리가 어렵습니다.
보안 문제
finalize 메서드를 악용해 보안 취약점을 유발할 수 있습니다.
Cleaner란 무엇인가?
cleaner는 finalizer 보다 더 예측 가능하고 성능에 미치는 영향이 적은 방식으로 객체 정리를 수행할 수 있도록 합니다.
import java.lang.ref.Cleaner;
class Resource {
private static final Cleaner cleaner = Cleaner.create();
private static class ResourceCleaner implements Runnable {
@Override
public void run() {
// 리소스 해제 코드
System.out.println("Resource cleaned");
}
}
private final Cleaner.Cleanable cleanable;
public Resource() {
cleanable = cleaner.register(this, new ResourceCleaner());
}
}
문제점
예측 불가능
cleaner도 가비지 컬렉션과 관련이 있어 정확히 언제 실행될지 예측할 수 없습니다.
이는 중요한 리소스 해제 작업에 적합하지 않습니다.
복잡성 증가
cleaner를 사용하면 코드가 복잡해질 수 있으며,
특히 리소스 정리를 명확히 해야 하는 경우에는 더 그렇습니다.
Avoid Finalizers
finalizer의 사용은 피하는 것이 좋습니다.
finalizer는 예측 가능성과 성능 문제로 인해 대부분의 경우 적절하지 않습니다.
대신, 명시적인 종료 메서드(예: close 메서드)를 사용하고, try-with-resources 구문을 활용해 리소스를 관리하는 것이 좋습니다.
Use Cleaner as a Safety Net
cleaner는 주로 명시적인 종료 메서드가 호출되지 않는 경우에 대비한 안전망으로 사용해야 합니다.
리소스를 명시적으로 해제할 수 없는 상황에서 최후의 수단으로 사용합니다.
대안: 명시적인 종료 메서드 사용
가장 좋은 대안은 명시적인 종료 메서드를 사용하는 것입니다.
이 방법은 객체가 더이상 필요하지 않을 때 명확히 리소스를 해제할 수 있도록 합니다.
일반적으로 close 메서드를 구현하고, AutoCloseable 인터페이스를 사용해 try-with-resources 구문을 활용합니다.
class Resource implements AutoCloseable {
public void use() {
// 리소스 사용 코드
}
@Override
public void close() {
// 리소스 해제 코드
System.out.println("Resource closed");
}
}
public class Main {
public static void main(String[] args) {
try (Resource resource = new Resource()) {
resource.use();
} // try-with-resources 구문이 끝날 때 자동으로 close 호출
}
}
결론
finalizer와 cleaner는 모두 객체가 더이상 필요하지 않을 때 정리 작업을 수행하는 방법을 제공합니다.
그러나 finalizer는 예측 가능성화 성능 문제로 인해 사용이 권장되지 않습니다.
대신, cleaner를 사용하여 리소스 해제를 처리하고, 가능하면 명시적인 종료 메서드와 try-with-resources 구문을 사용해 리소스를 관리하는 것이 좋습니다.
이를 통해 메모리 누수를 방지하고, 애플리케이션의 성능과 안정성을 유지할 수 있습니다.
'Effective Java' 카테고리의 다른 글
Effective Java | Item 9. try-finally보다는 try-with-resources를 사용하라 (0) | 2024.05.28 |
---|---|
Effective Java | Item 7. 다 쓴 객체 참조를 해제하라 (0) | 2024.05.27 |
Effective Java | Item 6. 불필요한 객체 생성을 피해라 (0) | 2024.05.27 |
Effective Java | Item 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2024.04.23 |
Effective Java | Item 4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (1) | 2024.04.23 |