Study

(Java) 참조 유형 (Strong Reference/ Soft Reference/ Weak Reference/ Phantom References)

Developer RyanKim 2020. 4. 22. 15:44

Java Strong Reference/ Soft Reference/ Weak Reference/ Phantom References

 

Java의 참조 유형에는 크게 4가지가 있습니다.

참조 유형에 따라 GC 실행 대상여부, 시점이 달라집니다.

 

1. Strong References (강한 참조)

2. Soft References (소프트 참조)

3. Weak References (약한 참조)

4. Phantom References (팬텀 참조)

 

아래로 갈수록 GC의 대상이 되는 경우와 실행되는 시점이 앞 당겨집니다.

 

1. Strong References (강한 참조)

Java의 기본 참조 유형입니다. 

MyClass obj = new MyClass ();

obj 변수가 참조를 가지고 있는 한, MyClass 객체는 GC의 대상이 되지 않습니다.

 

 

2. Soft References (소프트 참조)

MyClass ref = new MyClass();      

SoftReference<MyClass> softRef = new SoftReference<MyClass>(ref); 

// 이 시점에 GC의 실행 대상이 가능 
ref = null;

// JVM의 메모리가 부족하지 않아 GC 실행 대상이 되지 않은 경우
// null이 반환되지 않고 기존 객체가 반환됨
ref = softRef.get();

대상 객체를 참조하는 경우가 SoftReference 객체만 존재하는 경우 GC의 대상이 됩니다.
단, JVM의 메모리가 부족한 경우에만 힙영역에서 제거되고 메모리가 부족하지 않다면 굳이 제거하지 않습니다.

3. Weak References (약한 참조)

MyClass ref = new MyClass();      

WeakReference<MyClass> weakRef = new WeakReference<MyClass>(ref); 

// 이 시점에 GC의 실행 대상이 가능 
ref = null;

// 다음 GC 실행시 무조건 힙 메모리에서 제거
// 제거된 경우 null 반환
ref = softRef.get();

대상 객체를 참조하는 경우가 WeakReferences 객체만 존재하는 경우 GC의 대상이 됩니다.
다음 GC 실행시 무조건 힙 메모리에서 제거됩니다.

(톰캣 컨테이너의 ConcurrentCache class에서 WeakHashMap을 사용 중)


4. Phantom References (팬텀 참조)

 

    @Test
    public void test() {
        MyClass ref = new MyClass();

        ReferenceQueue<MyClass> refQueue = new ReferenceQueue<MyClass>();

        PhantomReference<MyClass> phantomRef = null;
        // 팬텀 참조는 아래처럼만 생성이 가능하다
        phantomRef = new PhantomReference<MyClass>(ref,refQueue);

        ref = null;

        System.gc();
		
        // 예상 : true
		// 실제 테스트: false
        System.out.println(phantomRef.isEnqueued());

        System.out.println(phantomRef.get()); // null

    }

 

생성자에서 무조건 ReferenceQueue를 받습니다. GC가 실행되기 전에 ( finalize() 호출 후)
PhantomReference는 객체 내부의 참조를 null로 설정하지 않고 참조된 객체를 phantomly reachable 객체로 만든 이후에 ReferenceQueue에 enqueue 됩니다.

 

다수의 포스트에서 PhantomReference는 잘 쓰이지 않고, 개념도 어렵다는 의견이 있어 저는 이정도로 넘어 갔습니다.

 

* 위 테스트 코드가 예상과 다르게 동작한 이유는 GC 수행시 참조 자체에 도달할 수 없는 경우는 큐에 넣지 않는다고 합니다.
https://stackoverflow.com/questions/48944818/why-is-phantom-reference-not-queued

 

자세한 테스트: https://knight76.tistory.com/entry/SofreReference-WeakReference-PhantomReference

 

 

참고

https://www.geeksforgeeks.org/types-references-java/

http://blog.breakingthat.com/2018/08/26/java-collection-map-weakhashmap/

https://knight76.tistory.com/entry/SofreReference-WeakReference-PhantomReference

https://c10106.tistory.com/3361

https://tourspace.tistory.com/42