이펙티브 자바 7

다 쓴 객체 참조를 해제하라

예시로 Java로 구현한 Stack의 코드를 살펴보자.


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

public Stack(){
	ensured = 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);
}

sizeindex로 사용하고 있다. 쌓여 있던 stackpop을 계속하여도 stack이 차지하는 메모리는 줄어들지 않는다.

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

pop을 통해 스택을 꺼낸 뒤, 해당 자리를 null로 설정해 GC가 발생할 때, 메모리가 정리되도록 코드를 변경할 수 있다.

주의점

매번, 변수를 사용하고 null값으로 변경하는 번거로운 과정은 않다도 된다. 예를 들어서 지역 변수로 선언된 변수들은 해당 스코프를 벗어나면 의미없는 래퍼런스 변수가 되어 GC에 의해서 정리되기 때문이다.

메모리를 직접 관리할 때

캐시

캐시 역시 메모리 누수를 일으키는 주범이다. 캐시 외부에서 키를 참조하는 동안만 엔트리가 살아 있는 캐시가 필요한 상황이라면 WeakHashMap을 사용하자. 다 쓴 엔트리는 자동으로 GC에 발생시 제거될 것이다.

콜백

마지막으로 흔하게 메모리 누수가 발생할 수 있는 지점으로 리스너와 콜백이 있다. 콜백을 Weak reference에 저장하자.

Strong reference로 객체를 생성했어도 Weak reference로 감싼다면, GC발생시 메모리가 수거될 수 있다.

Object key1 = new Object();
Object value1 = new Object();

/** **/
Map<Object, Object> cache1 = new HashMap<>();
cache1.put(key1, value1);

/** Weak reference로 감싸기**/
Map<Object, Object> cache2 = new WeakHashMap<>();
cache2.put(key1, value1);

첫번째 cache1은 더이상 key1 객체를 참조하지 않아도 GC의 대상이 될 수 없다. 하지만, cache2는 앞서 말했듯이 Weak reference로 감쌌기 때문에, GC의 대상이 될 수 있다.

좋은 웹페이지 즐겨찾기