- 프로그램에서 더 이상 사용하지 않는 객체는 GC(Garbage Collection) 대상이 된다. 하지만 그 객체들이 다 쓴 참조(obsolete reference)를 여전히 가지고 있다면, GC는 이를 회수 하지 못한다.
- 여기서 다 쓴 참조란 문자 그대로 앞으로 다시 쓰지 않을 참조를 뜻 한다. 가비지 컬렉션 언어에서는 (의도치 않게 객체를 살려두는) 메모리 누수를 찾는 것이 매우 까다롭다.
- 객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 그 객체가 참조하는 모든 객체를 회수해가지 못한다.
- 이를 해결하기 위해선 해당 참조를 다 썼을 때 null 처리(참조 해제)하면 된다.
- 일반적으로 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의해야 한다. 원소를 다 사용한 즉시 그 원소가 참조한 객체들을 다 null 처리해줘야 한다.
- 특히 긴 생명주기를 가진 데이터 구조(예: 캐시, 리스트 등)에서는 불필요한 객체 참조가 메모리 문제를 유발할 수 있으므로 주의가 필요하다. 캐시는 메모리 누수를 일으키는 주범이다.
public Object pop() {
if (size = 0)
throw new EmptyStackException();
Object result = elements[—size];
elements [size] = null;
return result;
}
- 객체가 더 이상 필요하지 않을 때는 참조를 명시적으로 해제하여 GC가 객체를 수집할 수 있도록 해야 한다.
- 이처럼 더 이상 필요 없는 객체에 대한 참조를 남겨두면 메모리 누수가 발생할 수 있다.
약한 참조와 강한 참조
WeakReference<String> weakReference = new WeakReference<>(new String("Weak"));
String strongReference = new String("Hello");
약한 참조(Weak Reference)
는 객체를 강하게 참조하지 않으며, 가비지 컬렉터가 객체를 언제든지 수거할 수 있는 참조 방식이다.
- 약한 참조는 객체의 수명을 연장하지 않으며, 객체가 더 이상 강하게 참조되지 않으면 GC가 이를 수거할 수 있다.
- 캐시 같은 메커니즘에서 자주 사용되며, 객체가 강하게 참조되지 않으면 GC에 의해 메모리를 회수하도록 설계할 때 유용하다.
강한 참조(Strong Reference)
는 Java에서 가장 일반적인 참조 방식이다. 객체를 변수에 할당하면 기본적으로 강한 참조가 생성된다.
import java.util.WeakHashMap;
public class WeakReferenceExample {
public static void main(String[] args) {
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
String value = "WeakHashMap Example";
map.put(key, value);
System.out.println("Before GC: " + map);
key = null;
System.gc();
System.out.println("After GC: " + map);
}
}
- WeakHashMap은 약한 참조를 사용하는 대표적인 클래스이다. 키에 대해 약한 참조를 적용하여, 키가 더 이상 강하게 참조되지 않을 때 해당 엔트리도 자동으로 제거된다.
- 강한 참조가 있는 객체는 가비지 컬렉터에 의해 수거되지 않는다. 참조가 유효한 한, 해당 객체는 메모리에서 계속 유지되며 GC는 이를 수거하지 못한다.
- 객체가 더 이상 필요하지 않을 때 명시적으로 참조를 해제해야먄 GC가 수거할 수 있다.
WeakHashMap 사용이 적합한 경우 : 캐시 구현, 임시 데이터 저장
- 자주 사용되지만 꼭 필요하지 않은 데이터를 저장할 때 유용하다. 예를 들어 데이터베이스 쿼리 로그를 메모리에 캐시하여 성능을 높이고, 메모리가 부족해지면 GC에 의해 자동으로 제거될 수 있도록 할 수 있다.
- 데이터가 필요없을 때 자동으로 메모리에서 해제되므로 메모리 누수를 방지할 수 있다.
결론
- 일반적으로 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의해야 한다.
- 원소를 다 사용한 즉시 그 원소가 참조한 객체들을 다 null 처리해줘야 한다.