Item7
다 쓴 객체 참조를 해제하라
- C나 C++와는 달리, 자바는 가비지 컬렉터(GC)가 다 쓴 객체를 알아서 회수해 준다.
- 메모리 관리에 더 이상 신경 쓰지 않아도 된다고 생각할 수 있으나, 절대 사실이 아니다.
1 메모리 누수 예시
Stack.java
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public Stack(int size) {
this.elements = new Object[size];
}
public void push(final Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0) {
return null;
}
return elements[--size];
}
public Object size() {
return this.elements.length;
}
private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, (size * 2) + 1);
}
}
}
- 위 코드는 특별한 문제가 없어 보이고, 테스트를 수행해도 통과할 것이다.
- 하지만 메모리 누수라는 문제가 숨어있는데, 이 스택을 오래 실행하다 보면 점차 가비지 컬렉션 활동과 메모리 사용량이 늘어나 결국 성능이 저하될 것이다.
- 심한 경우 디스크 페이징이나 OutOfMemoryError를 일으켜 프로그램이 예기치 않게 종료되기도 한다.
1.1 원인
- 위 코드에서 스택이 커졌다가(push), 줄어들때(pop) 스택에서 꺼내진 객체들을 가비지 컬렉터가 회수하지 않는다.
- 스택이 해당 객체들의 다 쓴 참조를 여전히 가지고 있기 때문이다
- 다 쓴 참조: 앞으로 다시 쓰지 않을 참조
- GC는 Unreachable한 객체를 찾을 수 있지만 Unused 한 객체를 찾을 수 없다
- 위에 다 쓴 참조가 Unused 한 객체이다
- Unused 한 객체는 프로그램의 논리에 따라 달라지므로 프로그래머는 비즈니스 코드에 주의해야 한다