본문 바로가기

IT/이펙티브자바 3E

[Effective Java] 아이템 7. 다 쓴 객체 참조를 해제하라.

안녕하세요 남갯입니다


오늘은 아이템 7. 다 쓴 객체 참조를 해제하라.

에 대해 작성해보려고 합니다.


public class Stack {

private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public Object[] getElements() {
return 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);
}
}

}


이코드에서 문제점을 찾아보자.


이 스택을 사용하는 프로그램을 오래 실행하다보면 점차 가비지 컬렉션 활동과 메모리 사용량이 늘어나 결국 성능저하가 된다. 심할경우 디스크 페이징이나 OOM error가 발생한다.

여기서 문제점은 이 커졌다가 줄어들었을 때 꺼내진 객체들을 가비지 컬렉터가 회수하지 않는다. 프로그램에서 그 객체들을 더 이상 하용하지 않더라도 활성역역 밖에 참조들 남아있다. 따라서 가비지 컬렉션 언어에서 메모리누수를 찾기 힘들다.


public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}


위와같이 해법은 객체의 참조를 다 썼을때 null로 메모리 참조 해제를 하면 된다.

null처리를 안하면 오류가 날 코드가 아니지만 null 처리를 함으로써 후에 나중에 발생가능한 NPE를 방지 할 수 있다. 


여기서 말하는것은 객체 참조를 무조건적으로 null 처리하게되면 코드가 더러워 지므로 객체 null 처리를 하는 일은 예외적인 경우가 되야한다.


다 쓴 참조를 해제하는 가장 좋은 방법은 그 참조를 유효범위 밖으로 밀어내는 것이다. 변수의 범위를 최소가 되도록 정의했다면 자연스럽게 이루어진다.


null처리는 언제할까?

Stack 클래스는 메모리를 직접 관리하기 때문에 메모리 누수에 취약하다. 이 스택은 저장소 풀을 만들어서 원소를 관리하기 때문이다. 따라서 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의해야한다. 또한 캐시 역시 메모리 누수의 주범이다. 


메모리 누수의 주범

1.메모리를 직접 관리하는 클래스

2. 캐시

3. 콜백과 리스너 (콜백을 등록하고 해지를 안해서..)