객체 생성과 객체 소멸
자바에서는 객체를 생성하는 new 연산자는 있지만 객체를 소멸시키는 연산자는 없다. 이런 이유로 자바에서는 개발자가 마음대로 객체를 소멸시킬 수 없다.
객체 소멸
new 키워드에 이해 생성된 객체 공간을 JVM에 돌려주어 가용 메모리(Available Memory)에 포함시키는 것이다. 다른 객체 지향 언어인 C++ 에서는 delete 키워드를 두고 있으며, delete 키워드가 실행되면 객체가 곧 바로 소멸된다. 그리고 객체가 소멸될 때 소멸자(Destructor) 메소드가 호출되어 객체가 사라질 때 필요한 마무리 작업을 수행하도록 한다.
-
Object 클래스의 finalize 메소드: 자바에서 소멸자와 가장 유사한 기능을 하는 메소드로 가비지 컬렉터에 의해 객체가 메모리에서 완전히 제거되기 직전에 호출되는 메소드이다.
-
finalize() 메소드: JVM의 영역 밖에서 할당된 관리되지 않은 자원(Unmanaged Resources)을 정리하는 것이다.
-
치명적인 단점: 가비지 컬렉터 실행 시점의 불확실성, 성능 저하, 예외 처리 문제, 객체 부활과 같은 단점으로 현대에는 사용이 권고되지 않는다.
가비지 컬렉션과 가비지 컬렉터의 차이
가비지 컬렉션과 컬렉터의 차이는 다음과 같다.
-
가비지 컬렉션: 자바 언어의 런타임 환경에서 수행되는 메모리 관리 과정 또는 행위 그 자체를 의미한다.
-
가비지 컬렉터: 가비지 컬렉션이라는 행위를 실제로 수행하는 주체, 즉 소프트웨어 에이전트를 의미한다. JVM의 내부에 내장된 서브 시스템 또는 프로그램 모듈로, 메모리에서 가비지 객체를 찾아내고 정리하는 작업을 책임지는 주체이다.
가비지
자바 응용 프로그램에서 더 이상 사용되지 않게 된 객체나 배열 메모리로, 참조하는 레퍼런스가 하나도 없는 객체나 배열을 가비지로 판단한다. 가비지의 발생에 대한 예제 코드는 다음과 같다.
package ch4n9;
public class GarbageExample {
public static void main(String[] args) {
String a = new String("Good"); // 지점 1
String b = new String("Bad"); // 지점 2
String c = new String("Normal"); // 지점 3
String d, e; // 지점 4
a = null; // 지점 5
b = c; // 지점 6, c 변수를 참조한다.
c = null; // 지점 7 c 변수 데이터는 없지만, b는 여전히 c를 참조한다.
}
}
위 코드를 실행하면 main() 메소드의 지점 4까지 초기 객체가 생성되면 ‘a’, ‘b’, ‘c’ 변수는 각각 “Good”, “Bad”, “Normal” 문자열 데이터를 메모리에 적재한다. 다음으로 지점 7까지 모든 구문을 실행하게 되면, ‘a’ 변수는 참조가 존재하지 않아 가비지가 발생되지만, ‘c’ 변수는 ‘a’ 변수와는 달리 ‘b’ 변수에 의한 참조 대상이므로 가비지로 처리되지 않는다.
자바의 가비지 컬렉션
가비지는 더 이상 참조되지 않기 때문에, 가비지가 차지하고 있는 메모리 공간은 회수 되어야 한다. 가비지가 많아지면 응용 프로그램에게 할당해줄 수 있는 가용 메모리의 양이 줄어들게 되기 때문이다. 자바 플랫폼은 가용 메모리가 일정 크기 이하로 줄어들면 자동으로 가비지를 회수하여 가용 메모리를 늘리고, 이것을 가비지 컬렉션이라고 부른다. 가비지 컬렉션은 자바 플랫폼에 의해 준비된 가비지 컬렉션 스레드에 의해 처리된다.
가비지 컬렉션 강제 요청
응용 프로그램에서 System 또는 Runtime 객체의 gc() 메소드를 호출하면 가비지 컬렉션을 요청할 수 있으나, 문장을 호출한 즉시 가비지 컬렉터가 작동하는 것은 아니다. 자바 플랫폼이 가비지 컬렉션의 호출 시기를 전적으로 판단하여 적절한 시점에 작동시킨다.
System.gc(); // 가비지 컬렉션을 강제로 요청한다. 호출 즉시 가비지 컬렉터가 작동되는 것은 아니다.