ITEM7 다 쓴 객체 참조를 해제하라
Garbage Collector
- 자바는 Garbage Collector 를 갖춘 언어
- 메모리를 직접 관리해야하는 C/C++과 달리, 다 쓴 객체를 알아서 회수해준다.
- JVM에서 GC의 스케줄링을 담당
- 객체는 힙 영역에 저장되고 스택 영역에 이를 가리키는 주소값이 저장되는데 참조되지 않는(자신을 가리키는 포인터가 없는, unreachable) 객체를 메모리에서 제거한다.
Person person = new Person(); person.setName("Mang"); // garbage 발생 person = new Person(); person.setName("MangKyu");
메모리 누수
- 컴퓨터 프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상
- Old 영역에 계속 누적된 객체로 인해 Major GC가 빈번하게 발생하게 되면서 성능 저하를 불러온다.
- 디스크 페이징이나 OutOfMemoryError 를 일으켜 프로그램이 종료될 수도 있다.
public Object pop() { if(size==0) throw new EmptyStackException(); return elements[--size]; }
public Object pop() { if(size==0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; return result; }
해결 방법(1) : null 처리
- 해당 참조를 다 썼을 때 null 처리(참조 해제)를 해주는 방법
- 사용이 끝난 참조에 실수로 접근하는 경우 NullPointerException을 내주는 효과도 있다.
- 예외적인 경우에만 사용하자 : 자기 메모리를 직접 관리하는 클래스의 경우
- 그 외에는 프로그램을 필요 이상으로 지저분하게 만들 뿐
해결방법(2) : 참조를 담은 변수를 유효 범위(scope) 밖으로 밀어내기
- 변수의 범위를 최소가 되게 정의하자
for(int i=0;i<10;i++){ }
기타 메모리 누수가 발생하는 상황 및 해결책
1) 캐시(cache)에 객체를 넣어두고 잊어버리는 경우
- java.lang.ref 패키지의 WeakReference 클래스를 사용하는 방법
WeakReference<Integer> A = new WeakReference<Integer>(new Integer(1)); Integer B = A.get() // B = 1 B = null; C = A.get(); // Integer 객체를 가리키는 참조가 WeakReference 객체 A 뿐 : 1은 GC 대상
- WeakHashMap 을 사용하는 방법
- 일반적인 HashMap의 경우 일단 Map안에 Key와 Value가 put되면 사용여부와 관계없이 해당 내용은 삭제되지 않는다.
- WeakReference를 이용해 HashMap의 Key를 구현하는 WeakHashMap을 이용하자
- 백그라운드 스레드(ScheduledThreadPoolExecutor)를 활용하는 방법
- 어떤 작업을 일정 시간 지연 후에 수행하거나, 일정 시간 간격으로 주기적으로 실행해야 할 때 사용
- 캐시에 새 엔트리를 추가할 때 부수 작업을 수행하는 방법
- LinkedHashMap 을 사용하는 방법 (removeEldestEntry)(10)
- 일정 사이즈가 차면 가장 오래된 값을 지우고, 그 자리에 방금 들어온 값을 대체 한다.
2) 콜백(callback) / 리스너(listener)
- 피호출자(Callee)가 호출자(Caller)를 다시 호출하는 함수 : 콜백함수
- 비동기적 처리를 하기 위한 디자인 패턴의 한 종류
- 콜백을 등록만 하고 명확히 해지하지 않는 경우 메모리 누수가 발생한다
- 콜백을 약한 참조로 저장하면 가비지 컬렉터가 즉시 수거해간다.
- WeakHashMap 에 키로 저장하는 방법