반응형

1. 스택

스택을 간단히 구현한 코드

메모리 누수가 일어나는 위치가 어디인가?

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);
    }

}

스택을 사용하는 프로그램을 오래 실행하다 보면 점차 가비지 컬렉션 활동과 메모리 사용량이 늘어나 결국 성능이 저하될 것임
스택이 커졌다가 줄어들었을 때 스택에서 꺼내진 객체들을 가비지 컬렉터가 회수하지 않음
스택이 그 객체들의 다 쓴 참조(obsolete reference)를 여전히 가지고 있기 때문임

해법

pop() 메서드 부분을 해당 참조를 다 썼을 때 null 처리(참조 해제) 하면된다.

public Object pop(){
    if(size == 0)
        throw new EmptyStackException();

    Object result = elements[--size];
    elements[size] = null;

    return result;
}

만약 null 처리한 참조를 실수로 사용하려 하면 프로그램은 즉시 NullPointerException을 던지면 종료

객체 참조를 null 처리하는 일은 예외적인 경우여야 한다.

자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수를 주의해야 함

2. 캐시

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

3. 리스너 혹은 콜백

클라이언트가 콜백을 등록만 하고 명확히 해지하지 않는다면, 뭔가 조치해주지 않는 한 콜백을 계속 쌓여갈 것임
콜백을 약한 참조(weak reference)로 저장하면 가비지 컬렉터가 즉시 수거해감

정리

메모리 누스는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 함
그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요

728x90

+ Recent posts