[Effective Java] 2장 객체 생성과 파괴 - 아이템 7. 다 쓴 객체 참조를 해제하라

배상규·2023년 9월 20일
0

이펙티브 자바

목록 보기
7/12
post-thumbnail

JAVA의 메모리 관리

C,C++ 와는 다르게 자바에서는 GC(가비지 컬렉터)을 통해 메모리를 회수해 가지만. 그렇다고 메모리 관리를 하지 않아도 된다고 오해해서는 절대 안된다

메모리 누수

public class Stack {
	private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    
    public Stack() {
    	this.elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }
    public void push() {
    	ensureCapacity();
        elements[size++] = e;
    }
    public Object pop() {
    	if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }
    // 공간이 부족할 시 2배로 공간을 확장한다.
    private void ensureCapacity() {
    	if (elements.length == size)
        	elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

간단한 스택을 구현한 코드이다. 특별한 문제는 없어 보이지만, 이스택을 사용하는 프로그램을 오래 실행하다 보면 가비지 컬렉션 활동과 메모리 사용량의 증가로 성능이 저하할것 이며, 심할 경우 OutOfMemoeryError을 일으킬 것이다.

그 이유는 pop 메서드를 통해 특정 객체를 꺼내 사용하여 메모리를 해제하는것이 아니라 push 메서드 사용시 그 위치에 덮어 씌우는 방식으로 프로그래밍 되어 있기 때문이다.

가비지 컬렉터의 경우 객체 참조를 살려두면 그 객체가 참조하는 모든 객체를 회수해가지 않는다. 그렇기 때문에 배열에서 참조 해제 시켜주지 않는다면 메모리 누수가 일어날 것이다.


참조 해제

그렇다면 이런 코드의 참조 해제 방법은 무엇이 있냐면

1. 다 쓴 참조에 null처리

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

위처럼 다 쓴 참조를 null 처리를 함으로 써, 메모리 누수가 없는 코드를 완성할 수 있다. 그거 의외의 이점으로, 만약 null 처리한 참조를 실수로 사용하려 하면 프로그램은 즉시 NullPointerException을 발생시켜 종료 시킬 것이다.

하지만 이는 코드를 필요 이상으로 더럽힐 것이다. 그렇기에 null 처리하는 일은 예외적인 경우여야 한다.

2. 유효 범위 처리

다 쓴 참조 해제중 가장 좋은 방법은 참조를 담은 변수를 유효 범위 밖으로 밀어내는 것이다.


마무리

이외에도 캐시, 리스너, 콜백의 경우에도 메모리 누수를 발생시킬 것이다. 따라서 이런 메모리 사용시 꼭 사용 해제를 해주어야 한다.

메모리 누수는 수년간 시스템에 잠복하는 경우도 있다. 이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원하여 발견되기도 한다. 그렇기에 이런 예방법을 익혀두는 것이 중요할 것이다.

profile
기록에 성장을

0개의 댓글