관리 메뉴

The Nirsa Way

[Effective Java 3/E - 객체 생성과 파괴] Item 7. 다 쓴 객체 참조를 해제하라 본문

Development/JAVA

[Effective Java 3/E - 객체 생성과 파괴] Item 7. 다 쓴 객체 참조를 해제하라

KoreaNirsa 2025. 6. 30. 20:15
반응형

 

다 쓴 객체 참조를 해제하라

메모리 누수(Member Leak)을 방지하기 위해 다 쓴 객체는 참조를 해제하라는 말 뜻입니다. 일반적으로 자바에서는 GC(Garbage Collector)가 객체를 회수하지만 GC의 특성상 "해당 객체를 참조하는 곳이 없어야 수거" 합니다.

즉, 더 이상 객체를 사용하지  않지만 어디선가 참조되고 있다면 GC는 해당 객체를 수거하지 않으며 메모리 누수가 발생하는 경우가 생길 수 있습니다. 예시는 아래와 같은 코드입니다.

public class Stack<E> {
    private Object[] elements;
    private int size = 0;

    public Stack() {
        elements = new Object[10];
    }

    public void push(E e) {
        ensureCapacity();  // 배열 길이가 부족할 경우 배열 확장
        elements[size++] = e;  // 요소를 배열에 추가한 후 size 값 증가
    }

    public E pop() {
        if (size == 0) throw new EmptyStackException();
        E e = (E) elements[--size];  // size 감소 후 요소 꺼내기
        return e;
    }

    // 배열이 꽉 찼을 경우 크기를 2배+1 만큼 늘려서 새 배열 생성
    private void ensureCapacity() {
        if (elements.length == size) {
            elements = Arrays.copyOf(elements, 2 * size + 1);
        }
    }
}

 

해당 코드에서 메모리 누수가 발생하는 지점은 아래 코드의 부분입니다. 마지막 요소를 꺼낸 후 size를 감소하지만, 여전히 elements 배열이 객체를 계속 사용중입니다.

E e = (E) elements[--size];  // 마지막 요소를 꺼낸 후 size 감소

예를들어 아래와 같은 과정을 통해 메모리 누수가 발생할 수 있습니다.

 

  1. 객체 생성 및 푸시 : stack.push(new Object())
  2. 위의 과정을 통해 elements[0]의 요소에 객체가 참조되며 size는 1이 됨
  3. 객체 pop : E e = (E) elements[--size];
  4. 위의 과정을 통해 size는 0이 되며 elenets[0] 요소를 변수 e에 넣음
  5. 지역 변수 e에 요소가 들어갔지만 elements[0]은 계속해서 객체를 참조중 (사라지지 않음)

위의 과정을 통해 GC는 elements[0]에 들어있는 해당 객체가 사용중임으로 간주하여 수거하지 않으며 이로 인해 메모리 누수가 발생합니다.

현재 코드에서 이러한 현상을 해결하는 방법은 간단합니다. 요소를 꺼낸 후 elements[0]이 여전히 객체를 참조중이기 때문에 발생하는 문제이니 elements[0]에다가 null을 넣어주시면 원래 있던 객체의 참조가 해제되어 메모리 누수를 예방할 수 있습니다.

E e = (E) elements[--size];  // 마지막 요소를 꺼낸 후 size 감소
elements[size] = null; // 참조 해제

 

반응형