[자바] 참조의 종류

June·2022년 3월 24일
0

우테코

목록 보기
25/84

학습 배경

이펙티브 자바에서 아이템 7. 다 쓴 객체 참조를 해제하라를 공부하다가 WeakHashMap이 나왔다. 찾아보다가 참조에도 종류가 있다는 걸 알게 되었다.

strong -> soft -> weak -> phantom 순이다.

Strong References

일반적으로 흔히 써왔던 것들이 강한 참조다.

StringBuffrer buffer = new StringBuffer();

위의 코드 실행 StringBuffer()를 생성 후 변수 buffer에 강한 참조를 저장한다.
여기서 '강한'은 가비지 컬렉터와 관련이 있다. 만약 객체가 강한 참조를 통해서 '닿을' 수 있다면 그것은 GC의대상이 아니다.

왜 Strong References는 너무 strong할까?

자바 프로그래밍에서 종종 더 이상 extend 할 수 없는 클래스들을 사용한다 (final이 붙은 클래스.. )

예를 들어서 Widget이라는 확장 불가능한 클래스를 사용하는데, 어떤 기능을 추가한다고 생각해보자.
만약 Widget의 일련 번호를 관리하는 정보를 관리해야 한다고 하자. 그러면 클래스에는 새로운 프로퍼티를 추가하지 못하기 때문에 아래와 같이 할 것이다.

serialNumberMap.put(widget, widgetSerialNumber);

일단 표면상으로는 괜찮아 보이는데, 우리는 언제 이 위젯의 일련 번호가 더 이상 필요하지 않는지 알아야 한다. 그래야 우리는 맵의 엔트리에서 제거할 수 있다. 그렇지 않으면 메모리에 누수가 생긴다. 이 문제는 GC를 사용하지 않는 언어를 사용하는 개발자들이 마주하는 문제다.

다른 문제는 캐싱을 이용할 때다. 캐시는 메모리에 올라간 데이터에 대해 참조를 항상 하고 있다. 강한 참조로는 메모리에 항상 있게하므로, 언제 필요 없을 때 GC가 될 것인지 결정해야 한다.

Weak References

약한 참조는 메모리에 객체가 있게 유지할 정도로 강하지 않은 참조다.

WeakReference weakWidget = new WeakReference(widget);

위의 코드처럼 쓰면 되고, weakWidget.get()을 써서 객체를 가져올 수 있다.
물론 약한 참조는 메모리에 항상 있지 않게 하므로 언젠가 GC를 당해서 null을 반환할 수 있따.

강한 참조에서 나왔던 시리얼 번호 관리 문제를 풀기 위해서는 WeakHashMap을 사용하면 된다.
WeakHashMapHashMap과 동작은 비슷하지만, 키를 약한 참조로 저장하는 것이다.
만약 키가 GC 당하면, Value도 GC 당한다.

Refernece queues

WeakReference에서 만약 참조 대상이 사라지면 참조 변수가 필요 없어진다. 그래서 청소가 필요하다.

RefereneceQueue 클래스가 필요 없어진 참조 변수들을 추적한다. 그래서 실행을 하면 정리하는 일을 한다.

Soft References

soft reference는 weak reference랑 비슷하지만, soft 보다는 참조 객체를 버리는 것을 덜한다.
soft refernece의 대상은 메모리가 충분하면 남아 있는다. 그래서 캐시 같은 것을 사용할 때 유용하다.

Phantom References

팬텀 참조는 참조가 너무 희박해서 객체에 참조가 되지도 않는다. 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

0개의 댓글