[책리뷰/Effective Java] 객체 생성과 파괴

OCTOBER 04, 2020

아이템7) 다 쓴 객체 참조를 해제하라

메모리 누수는 겉으로 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다.
이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 한다.
그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다.

메모리 누수 발생 코드

public class Stack {
  private Obejct[] 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);
  }
}

해결방법

  • Object[]은 Arrays.copyOf()를 통해 길이조절이 되는 상황이다.
    pop() 메소드에서 size를 감소시키나, 해당 값은 그대로 두고 있으므로 메모리 누수가 발생하는 것을 볼 수 있다.
    이 경우 명시적으로 null 을 할당해줌으로써 참조해제를 통해 GC를 돌릴 수 있다.
  public Object pop() {
    if(size == 0) throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // 참조값인데.... result도 null이 아닌가?? 확인 필요
    return result;
  }

메모리 누수 주범

  • 자기 메모리를 직접 관리하는 클래스
  • 캐시
  • 리스너 혹은 콜백

메모리 누수 예방법

  • 원소를 다 사용한 즉시 그 원소가 참조한 객체들을 null 처리 한다.
  • WeakHashMap 또는 LinkedHashMap의 removeEldestEntry() 를 사용
  • 백그라운드 스레드 활용 (ScheduledThreadPoolExecutor)
참고

작업 기록 블로그