본문 바로가기
Java/Effective Java 3E

[이펙티브자바 3판] ITEM7. 다 쓴 객체 참조를 해제하라 (메모리 누수)

by 잭피 2020. 9. 7.

이번장의 핵심은...

자바가 가비지 컬렉터를 갖춘 언어이지만, 

메모리 관리에 신경쓰지 않으면, 메모리 누수가 일어날 수 있다


다른 언어를 쓰다가 자바처럼 가비지 컬렉터를 갖춘 언어로 넘어오면,

자칫 메모리 관리에 더 이상 신경 쓰지 않아도 된다고 오해할 수 있다

 

아래 자료구조 Stack에서 데이터를 꺼낼 때 쓰는 pop() 메소드를 예로 들어보자

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

 

별로 문제가 없어보이지만, '메모리 누수' 라는 문제가 있다

결국 성능이 저하될 것이고 디스크 페이징 or OutOfMemoryError를 일으킬 수 있다

해당 참조를 다 썼다면, 아래 코드처럼 null처리 (참조해제)를 해주자

public class Stack {
	private Object[] elements;
    
    public Object pop() {
    	if(size=0) throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // 다 쓴 참조를 해제해준다
        return result;
  }
}

그런데 모든 객체를 다 쓰자마자 일일이 null처리를 해야하나?

그건 프로그램을 필요 이상으로 지저분하게 만든다

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

 

null 처리는 언제?

위의 스택은 자기 메모리를 직접 관리한다

이 스택은 객체 자체가 아닌, 객체 참조를 담는 elements 배열로 저장소 풀을 만들어 원소를 관리한다

배열의 활성 영역에 속한 원소들이 사용되고 비활성 영역은 사용되지 않는다 

여기서 문제는 가비지 컬렉터는 이 사실을 알 길이 없다 

 

가비지 컬렉터가 보기엔 비활성 영역에서 참조하는 객체도 똑같이 유효한 객체다

비활성 영역의 객체가 더 이상 쓸모없다는 건 프로그래머만 아는 사실이다

 

즉, 프로그래머는 비활성 영역이 되는 순간 null 처리해서 해당 객체를 더는 쓰지 않을 것임을 가비지 컬렉터에게 알려야 한다

 

일반적으로 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의하자 

 

메모리 누수의 주범

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

2. 캐시 

캐시를 사용하고 그대로 두는 일이 자주 있다

ex) WeakHashMap을 사용하자 (다 쓴 엔트리는 그 즉시 자동으로 제거)

3. 리스너 혹은 콜백

클라이언트가 콜백을 등록만 하고 명확히 해지 하지 않는다면, 콜백은 계속 쌓임

이럴 때 콜백을 약한 참조로 저장하면 가비지 컬렉터가 즉시 수거 

ex) WeakHashMap을 사용하자 (다 쓴 엔트리는 그 즉시 자동으로 제거)

 

 

 

 

댓글