Java에서 메모리 관리는 JVM이 자동으로 해준다. 가비지 컬렉션(GC)이라는 기능을 통해 사용하지 않는 객체를 찾아내 메모리를 회수한다. 이 과정은 메모리 효율성을 높여주고, 메모리 누수를 방지하는 데 큰 역할을 한다.
힙(Heap) 영역에 생성된 객체 중에서 더 이상 어떤 참조 변수도 가리키지 않는 객체를 가비지로 판단하고 회수한다. 이를 위해 가비지 컬렉터는 'Reachability Analysis'라는 방법을 사용해 GC Root로부터 시작하여 접근할 수 없는 객체를 찾아낸다.
객체가 가비지로 판단되어 회수되기 직전에 finalize() 메소드가 호출된다. 여기서 리소스 해제 같은 정리 작업을 할 수 있지만, 여러 문제가 있다.
변수를 null로 설정하면, 해당 변수가 참조하던 객체는 더 이상 참조되지 않는 상태가 된다. 이 상태가 되면 객체는 가비지 컬렉션의 대상이 될 수 있다. 하지만 이는 가비지 컬렉터가 실행되는 시점에 따라 다르다.
public class GarbageCollectionExample {
public static void main(String[] args) {
MyClass obj = new MyClass("Test");
obj = null; // obj가 참조하던 MyClass 인스턴스를 가비지 컬렉션의 대상으로 만든다.
// 가비지 컬렉터 호출 요청 (실제 호출 시점은 JVM이 결정)
System.gc();
// 대기 시간 추가 (finalize() 호출 확인용)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private static class MyClass {
private String name;
public MyClass(String name) {
this.name = name;
}
@Override
protected void finalize() {
System.out.println(name + " 객체의 finalize()가 실행됨");
}
}
}
이 예제에서 MyClass 인스턴스를 생성하고, null을 할당해서 가비지 컬렉션 대상으로 만든다. System.gc()를 호출해 가비지 컬렉터를 요청하지만, 실제 가비지 컬렉션이 일어나는 시점은 JVM이 결정한다. finalize() 메소드에서는 간단한 메시지를 출력해 호출 여부를 확인할 수 있다.
이 예제와 설명을 통해 Java의 가비지 컬렉션과 finalize() 메소드의 사용 시 주의해야 할 점들을 잘 이해할 수 있다. finalize() 대신 자바 7부터 제공하는 try-with-resources를 사용하는 것이 좋다. 이를 통해 리소스를 보다 안전하고 효율적으로 관리할 수 있다.
Java는 다양한 가비지 컬렉터를 제공하며, 각각의 가비지 컬렉터는 특정 유형의 애플리케이션에 더 적합할 수 있다.