- 한줄 요약 : 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항시 메모리 누수에 주의 해야한다.
(1) 문제 코드
public class Stack {
// stack 구현 일부
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public Object pop(){
if(size == 0 )
throw new EmptyStackException();
return elements[--size];
}
}
- 코드 문제점
- 스택이 자기 메모리를 직접 관리한다.
- 스택은 elements 배열로 저장소 풀을 만들어 원소들 관리
- pop()을 해도 스택의 size를 벗어난 활성영역 밖의 참조들을 여전히 가지고 있다.
- 비활성 영역이라는건 우리만 알지 가비지 컬렉터는 모른다.
- 따라서 가비지 컬렉터가 회수하지 않는다. -> 잠재적으로 성능 저하
- 스택이 자기 메모리를 직접 관리한다.
(2) 개선 코드
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
// stack 구현 일부
public Object pop(){
if(size == 0 )
throw new EmptyStackException();
elements[size] = null; // 추가
return elements[--size];
}
}
- 객체를 null 처리하는 일은 예외적인 경우여야함. (프로그램 지저분해져서)
- 그럼 언제 null 처리를?
- 메모리를 직접 관리하는 클래스의 경우에 비활성 영역이 되는 순간 null 처리해서 가비지 컬렉터에 알려야함.
- 메모리 누수 주범들
- 캐시
- 캐시에 넣고 다 쓴 뒤로도 한참을 그냥 놔두면..
- 해결 방법 : WeakHashMap을 사용하여 캐시만들자.
- 리스너 혹은 콜백
- 해결 방법 : 약한 참조(weak reference)로 콜백 저장하자
- 캐시
- java의 3가지 reference 방식
- 강한 참조 (strong reference)
- GC의 대상에서 제외
- 일반적인 참조 유형
- ex)
Integer prime = 1
- ex)
- 부드러운 참조 (soft reference)
- GC에 의해 수거될 수도, 안될 수도 있다.
- out of memory 시점에 가깝다면 수거 확률 높음
- SoftRefrence 객체로 생성
- GC에 의해 수거될 수도, 안될 수도 있다.
- 약한 참조 (weak reference)
- GC가 발생하면 무조건 수거된다.
- 메모리가 안 부족해도 무조건
- WeakReference 객체로 생성
- GC가 발생하면 무조건 수거된다.
- 강한 참조 (strong reference)
- WeakHashMap
- 일반적인 HashMap의 경우 일단 Map안에 Key와 Value가 put되면 사용여부와 관계없이 해당 내용은 삭제되지 않는다.
- WeakHashMap은 WeakReference의 특성을 이용하여 HashMap의 Element를 자동으로 제거
- 용어 조사(weakHashMap, weak reference)