이펙티브 자바에서 아이템 7. 다 쓴 객체 참조를 해제하라를 공부하다가 WeakHashMap
이 나왔다. 찾아보다가 참조에도 종류가 있다는 걸 알게 되었다.
strong -> soft -> weak -> phantom 순이다.
일반적으로 흔히 써왔던 것들이 강한 참조다.
StringBuffrer buffer = new StringBuffer();
위의 코드 실행 StringBuffer()
를 생성 후 변수 buffer
에 강한 참조를 저장한다.
여기서 '강한'은 가비지 컬렉터와 관련이 있다. 만약 객체가 강한 참조를 통해서 '닿을' 수 있다면 그것은 GC의대상이 아니다.
자바 프로그래밍에서 종종 더 이상 extend 할 수 없는 클래스들을 사용한다 (final이 붙은 클래스.. )
예를 들어서 Widget
이라는 확장 불가능한 클래스를 사용하는데, 어떤 기능을 추가한다고 생각해보자.
만약 Widget
의 일련 번호를 관리하는 정보를 관리해야 한다고 하자. 그러면 클래스에는 새로운 프로퍼티를 추가하지 못하기 때문에 아래와 같이 할 것이다.
serialNumberMap.put(widget, widgetSerialNumber);
일단 표면상으로는 괜찮아 보이는데, 우리는 언제 이 위젯의 일련 번호가 더 이상 필요하지 않는지 알아야 한다. 그래야 우리는 맵의 엔트리에서 제거할 수 있다. 그렇지 않으면 메모리에 누수가 생긴다. 이 문제는 GC를 사용하지 않는 언어를 사용하는 개발자들이 마주하는 문제다.
다른 문제는 캐싱을 이용할 때다. 캐시는 메모리에 올라간 데이터에 대해 참조를 항상 하고 있다. 강한 참조로는 메모리에 항상 있게하므로, 언제 필요 없을 때 GC가 될 것인지 결정해야 한다.
약한 참조는 메모리에 객체가 있게 유지할 정도로 강하지 않은 참조다.
WeakReference weakWidget = new WeakReference(widget);
위의 코드처럼 쓰면 되고, weakWidget.get()
을 써서 객체를 가져올 수 있다.
물론 약한 참조는 메모리에 항상 있지 않게 하므로 언젠가 GC를 당해서 null
을 반환할 수 있따.
강한 참조에서 나왔던 시리얼 번호 관리 문제를 풀기 위해서는 WeakHashMap
을 사용하면 된다.
WeakHashMap
은 HashMap
과 동작은 비슷하지만, 키를 약한 참조로 저장하는 것이다.
만약 키가 GC 당하면, Value도 GC 당한다.
WeakReference에서 만약 참조 대상이 사라지면 참조 변수가 필요 없어진다. 그래서 청소가 필요하다.
RefereneceQueue
클래스가 필요 없어진 참조 변수들을 추적한다. 그래서 실행을 하면 정리하는 일을 한다.
soft reference는 weak reference랑 비슷하지만, soft 보다는 참조 객체를 버리는 것을 덜한다.
soft refernece의 대상은 메모리가 충분하면 남아 있는다. 그래서 캐시 같은 것을 사용할 때 유용하다.
팬텀 참조는 참조가 너무 희박해서 객체에 참조가 되지도 않는다. get()
메서드를 사용하면 항상 null
을 반환한다.
WeakReference
와 비슷하지만 큐에 들어갈 때 차이가 생긴다. Weak Reference 대상은 참조 대상이 약하게 참조가 되자마자 큐에 들어간다. 이건 finalization
이나 GC가 일어나기 전이다.
PhantomReference
는 물리적으로 메모리에서 제거될 때만 큐에 들어간다.
PhantomReference
의 장점은 언제 객체가 메모리에서 사라져야하는지 결정하게 해준다. 평소에는 안유용하지만 큰 이미지 캐싱 같을 때 유용하다. OutOfMemoryError
같은 에러를 방지할 수 있다.
두번째 장점은 finalize
의 근본적인 문제를 막아준다. finalize()
메서드는 "부활" 문제를 막는다. 가비지 컬렉션에서 왔다갔다 하다가 부활이되는 것이다. 만약 부활되면 다시 처음부터 gc가 돌아야한다. 이런 문제 때문에 가 힙이 대부분 garbage여도 OutOfMemoryErrors
가 발생한다.
http://euler.mat.uson.mx/~havillam/java/Common/Understanding-Weak-References.pdf