카테고리 없음

[Effective Java 3/E - 객체 생성과 파괴] Item 8. finalizer와 cleaner 사용을 피하라

KoreaNirsa 2025. 6. 30. 21:12
반응형

 

finalizer와 cleaner 사용을 피하라

객체 소멸자 finalizer와 cleaner는 GC에 의해 실행되며 실행 시점 보장이 없기에 예측되지 않습니다. 즉 GC의 알고리즘에 따라 천차만별이며 테스트 과정의 JVM에서는 잘 동작 했지만 배포된 서버에서는 정상적인 동작을 하지 않아 문제가 발생할 수 있습니다.

아래의 코드는 finalize()의 예시 코드이며 객체 생성한 다음 참조 해제하여 gc를 요청하는 코드입니다. 즉 gc는 obj 객체의 참조가 비워져 있으므로 메모리를 수거하려고 할 것 입니다. 또한 finalize()를 오버라이딩 했음으로 GC가 해당 객체를 수거할 때 finalize() 메서드가 호출됩니다.

public class Test {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize() 호출됨");
    }

    public static void main(String[] args) throws InterruptedException {
    	Test obj = new Test();
        obj = null;
        System.gc();

        System.out.println("GC 요청");
        Thread.sleep(3000); 
        System.out.println("프로그램 종료");
    }
}

여러번 실행해보면 각기 다른 요청을 하게 되는데 finalize()는 어떤 스레드가 호출할지도 모르며, 어떠한 시점에 실행될지도 보장하지 않습니다. 이러한 특징은 clanner도 같으며 이로 인해 성능 저하도 초래할 수 있으며 clanner도 동일한 특징을 가집니다.

같은 코드임에도 다른 응답 결과

이러한 이유로 finalize()는 여러 가지 문제를 발생시켜 Java9 이후로 deprecated 되었습니다.

Object.class

 


 

그럼 객체 소멸은 어떤걸 써야 하는가?

가장 대표적으로 권장하는 방식은 try-with-resources 입니다. 아래의 코드를 직접 실행해 보면 몇번을 실행하던지 try 블록이 끝나면서 close()를 호출하여 객체를 소멸시킵니다. 즉, 예외 발생 여부와 상관 없이 try 블록이 끝나는 순간 객체는 소멸합니다.

class DummyResource implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("close() 호출됨");
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException {
        try (DummyResource res = new DummyResource()) {
            System.out.println("자원 사용 중");
            Thread.sleep(3000); 
        }
    }
}

여러번 실행해도 같은 결과

 

참고로 DummyResource에서 상속받고 있는 AutoCloseable은 try-with-resources 구문에서 자동으로 close()를 호출하기 위해 사용되는 인터페이스 입니다. 즉, 어떠한 객체를 사용은 하되 try 블록에서 객체를 사용 후 자원 누수 없이 객체를 소멸하고 싶다면 AutoCloseable 인터페이스를 상속받아 close() 메서드를 오버라이딩하면 됩니다.

 

반응형