[Effective Java] 6. 객체 참조 폐기

1 분 소요

GC가 있는 Java의 경우 메모리 관리를 망각하는 경우가 많다.
하지만 실수에 의해 불필요한 참조가 제거되지 않아 Memory leak이 발생할 수 있다.

private Object[] elements;
private int size = 0;

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

위와 같은 Stack의 pop은 메모리 누수가 발생한다.
Pop 할때 Object 배열에서 index만 조절하였을 뿐 실제 배열에있는 Object는 그대로 남기 때문이다.

Stack의 특성상 배열 index인 size보다 큰 곳에 위치한 Object를 사용하지 않겠지만 사용하지 않을뿐 참조가 제거된 것은 아니다.

실수로 reference가 계속 유지되는 경우 해당 객체만 GC되지 않는 것이 아니라 이 객체와 연관된 다른 객체들도 GC 대상에서 제외된다.

참고로 위 문제는 간단하게 수정이 가능하다.

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

1. 만기 객체 참조를 없애는 좋은 방법

위와 같이 객체에 null 처리를 하는 것은 예외적인 조치이지 모든 객체에 해야 하는 룰이 아니다.
오히려 모든 객체에 대해 사용 이후 null처리를 하게 되면 코드만 난잡해 진다.

만기된 객체의 참조를 없애는 좋은 방법은 해당 변수가 참조되는 scorp를 가능한 좁게 만드는 것이다. 변수의 범위를 좁히면 자연스럽게 memory leak 발생 가능성을 줄인다.

2. Memory leak 발생 가능성이 큰 경우

2.1. 자체적으로 메모리를 관리하는 Class

위 Stack의 예와 같이 자체적으로 관리하는 메모리가 있는 Class는 이런 Memory leak 발생 가능성이 높다.
따라서 이런 Class를 만들때는 특히나 주의해야 한다.

2.2. Cache

캐시도 메모리 누수가 발생하는 흔한 경우이다. 객체 참조를 캐시에 넣어두고 잊어버리는 경우가 많기 때문이다.

2.3. Listener

Listener와 같은 Callback을 사용하는 경우도 메모리 누수가 발생하는 흔한 경우이다.
Listener 등록만 하고 제거를 하지 않으면 메모리를 계속 점유하게 된다.

Listener를 처리하는 가장 좋은 방법은 Listener를 Weak Reference로 저장하는 것이다.

댓글남기기