[Effective Java] Item 7. 다 쓴 객체 참조를 해제하라
다 쓴 객체 참조를 해제하라
JAVA는 C, C++처럼 메모리를 직접 관리해주지 않아도 상황에따라 가비지 컬렉션이 작동하여 메모리를 정리해준다.
그래서 개발할때 메모리 관리에 신경을 쓰지 않아도 된다라고 오해할 수 있는데 잘못된 생각이다.
메모리 관리에 신경쓰지 않고 개발시 문제점
사용하지 않는데 값을 계속 참조하고있으면 가비지 컬렉션이 해당 값을 정리하지 못한다.
그렇게되면 메모리 사용량이 늘어나 성능이 저하되고 심할때는 디스크 페이징이나 OutOfMemoryError를 일으켜 프로그램이 종료 될 수 있으므로 다 쓴 참조는 null 처리 해주는게 좋으며 재 참조시 NullPointException을 발생시켜 조기에 문제점을 찾을 수 있다.
자기메모리를 직접 관리하는 클래스 사용시 주의할점
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
위 코드는 보기에는 멀쩡해 보이나 이 코드에는 문제점이 하나 있다.
바로 스택이 줄어들때 (pop() 호출시) 단순 size값만 변경시켜 해당 값을 참조를 못하게 했을뿐 실제로는 아직 값을 참조 하고 있다는 문제다.
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object value = elements[--size];
elements[size] = null;
return value;
}
이렇게 더 이상 사용하지 않는 값은 null을 참조하게 만들어야 가비지 컬렉션이 정리할 수 있다.
위 처럼 자기메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의 해야한다.
캐시 역시 메모리 누스를 일으키는 주범이다.
객체 참조를 캐시에 넣어두고 그 객체를 다 쓴 뒤에도 한참을 놔두면 메모리 누수가 발생한다.
캐시 외부에서 키를 참조하는 동안만 엔트리가 살아있는 캐쉬가 필요하다면 WeakHashMap을 사용해 캐쉬를 만들자
캐시 엔트리의 유효기간을 정확히 알기 어려으므로 시간이 지날수록 엔트리의 가치를 떨어뜨리는 방식을 사용해야 하는데 이때는 ThreadPoolExecutor같은 백그라운드 스레드를 활용하거나 새 엔트리를 추가 할 때 부수 작업으로 청소를 수행하는 방법이 있다.
리스너(listener) 와 콜백(callback)도 메모리 누수를 일으키는 주범이다.
클라이언트가 콜백을 등록만 하고 명확히 해지 않거나 뭔가 조치를 해주지 않는 한 콜백은 계속 쌓여갈것이다.
이떄는 week refernce로 저장하면 가비지 컬렉터가 즉시 수거해간다.