Search

Item 7. 다 쓴 객체 참조를 해제하라

생성일
2023/07/27 10:35
챕터
2장 - 객체 생성과 파괴

메모리 누수의 원인들

자바에서는 가비지 컬렉터를 통해 더 이상 사용하지 않는 자원들에 대해 자동적으로 수거된다.
하지만 객체들을 다 사용하고 나서도 참조를 해제 하지 않는다면, 가비지 콜렉터는 해당 객체를 사용하고 있다고 판단해 수거를 하지 않고 메모리 누수로 이어진다.
아래는 스택을 구현한 코드이다.
public class Stack { private Object[] elements; private int size = 0; ... public Object pop() { if (size == 0) throw new EmptyStackException(); return element[--size]; } }
Java
복사
위와 같이 pop 메서드를 구현하면, 실제 element는 줄어든 size까지만 사용되는데 그 뒤의 배열에는 여전히 참조가 남아있기 때문에 메모리 누수가 발생한다.
가비지 컬렉션 언어에서는 메모리 누수를 찾기가 상당히 까다로운데, 그렇기 때문에 아래처럼 다 쓴 객체는 null 처리(참조 해제)하자.
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // 다 쓴 참조 해제 return result; }
Java
복사
이처럼 다쓴 참조 객체를 null 처리하면, 실수로라도 해당 참조를 사용할 때 NullPointerException이 발생해서 오동작 하지 않고 잘못된 사용임을 개발자에게 알릴 수 있다.
객체 참조를 다 사용했다고 하여 무조건적으로 null 처리하는 것은 바람직하지 않고, 예외적인 경우에만 사용하자.
위의 Stack 클래스의 경우에는 내부에 멤버 변수로 원소들의 배열을 들고 자기가 직접 관리한다. 이와 같은 경우에는 가비지 컬렉터가 비활성 영역인지 아닌지 알 수 없기 때문에 메모리를 수거해가지 않는다.
그러니 이처럼 자기가 메모리를 직접 관리하는 클래스인 경우에는 메모리 누수에 주의하자.
캐시 또한 메모리 누수를 자주 발생시키는데, 데이터를 캐싱 후 한참동안 해제하지 않고 놔두는 일이 흔하기 때문이다.
WeakHashMap은 엔트리가 살아있는 동안 캐시를 사용하고, 다 쓴 엔트리는 즉시 제거한다.
이처럼 시간이 지날 수록 엔트리의 가치를 떨어뜨리는 방식으로, 엔트리를 가끔씩 청소해주어야 한다.
리스터(listener) 혹은 콜백(callback) 또한 메모리 누수를 발생시킬 수 있다. 콜백을 등록 후 명확히 해지하지 않으면, 콜백을 계속 쌓여갈 것이다.
콜백을 약한 참조(weak reference)로 저장하면 가비지 컬렉터가 즉시 수거해가니, WeakHashMap에 키로 저장하는 방식을 사용하자.