일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- mst
- 플로이드-와샬
- swea
- 투 포인터
- 후니의 쉽게 쓴 시스코 네트워킹
- 이분탐색
- 백트래킹
- 그리디
- 프로그래머스
- java
- Effective Java
- 유니온 파인드
- JUnit 5
- 문자열
- 위상정렬
- 세그먼트 트리
- dfs
- 스택
- 동적계획법
- 에라토스테네스의 체
- 완전탐색
- BFS
- 수학
- 백준
- Kotlin
- 구현
- 알고리즘
- 시뮬레이션
- Network
- CS
반갑습니다!
[Java] Java Reference 본문
참조 유형
Java의 참조 유형에는 크게 4가지가 있다. 그리고 이 유형에 따라서 GC 실행 대상 여부와 실행 시점이 달라진다.아래
위에서 아래로 갈수록 GC의 대상이 될 확률이 높아지고 실행 시점이 앞당겨진다.
- Strong Reference (강한 참조)
- Soft Reference (소프트 참조)
- Weak Reference (약한 참조)
- Phantom Reference (팬텀 참조)
Strong Reference (강한 참조)
일반적으로 Java에서 new
키워드를 사용해서 객체를 생성했을 때 '강한 참조'가 된다.
SampleObject obj = new SampleObject();
위의 코드에서 obj
변수가 SampleObject
객체의 참조를 가지고 있는 동안에는 해당 객체는 GC의 대상이 되지 않는다.
Soft Reference (소프트 참조)
public void softReferenceTest() {
SampleObject obj = new SampleObject();
SoftReference<SampleObject> ref = new SoftReference<>(obj);
obj = null;
System.gc(); // 테스트를 위해 강제로 GC호출
// 메모리가 충분한 경우 GC의 실행 대상이 되지 않음
// null이 아닌 기존의 객체가 반환
obj = ref.get();
System.out.println(obj == null ? "null" : "not null");
}
/*
실행 결과
not null
*/
강한 참조와는 다르게 GC에 의해 수거될 수도 있고, 수거되지 않을 수도 있다. 메모리에 충분한 여유가 있다면 GC가 수행되더라도 수거되지 않는다. 만약 Out of Memory
의 시점에 가깝다면 수거될 확률이 높다.
Weak Reference (약한 참조)
약한 참조는 GC가 발생하면 무조건 수거된다. 약한 참조가 사라지는 시점이 GC의 실행 주기와 일치하고, 이를 이용해 짧은 주기에 자주 사용되는 객체를 캐시할 때 유용하다. (실제로 톰캣 컨테이너의 ConcurrentCache class
에서 WeakHashMap
을 사용한다고 한다)
public void softReferenceTest() {
SampleObject obj = new SampleObject();
WeakReference<SampleObject> ref = new WeakReference<>(obj);
obj = null;
System.gc(); // 테스트를 위해 강제로 GC호출
// Weak Reference는 GC의 대상이 되므로 null 반환
obj = ref.get();
System.out.println(obj == null ? "null" : "not null");
}
/*
실행 결과
null
*/
Phantom References (팬텀 참조)
Reference Queue
팬텀 참조를 이해하기 위해서는 Reference Queue
(설명의 편의를 위해 RQ
라고 하겠다)에 대해서 이해할 필요가 있다. SoftReference / WeakReference 객체가 참조하는 객체가 GC 대상이 되면 참조는 null
이 되고 SoftReference / WeakReference 객체는 RQ
에 enqueue
된다. RQ
에 enqueue
하는 작업은 GC에 의해 자동으로 수행된다. RQ
에 SoftReference / WeakReference 객체가 enqueue
되었다는 것을 확인하면 참조하던 객체가 GC되었는지 확인할 수 있고, 이에 따라 관련된 리소스나 객체에 대한 후처리 작업을 할 수 있다.
SoftReference와 WeakReference는 RQ
를 사용할 수도 있고 사용하지 않을 수도 있다. 이는 생성자 중에서 RQ
를 인자로 받는 생성자를 사용하느냐 아니냐로 결정한다. 그러나 PhantomReference의 생성자는 단 하나이므로 반드시 RQ
를 사용해야만 한다.
SampleObject object = new SampleObject();
ReferenceQueue rq = new ReferenceQueue<>(); PhantomReference pr = new PhantomReference<>(object, rq);
위에서 언급했듯이 SoftReference, WeakReference는 내부의 참조가 null
이 된 이후에 RQ
에 enqueue
된다. 하지만 PhantomReference는 내부의 참조를 null
로 설정하지 않고 참조된 객체를 phantomly reachable 객체로 만든 뒤에 RQ
에 enqueue
된다.
PhantomReference
GC 대상 객체를 처리하는 작업과 할당된 메모리를 회수하는 작업은 연속된 작업이 아니다. GC 대상 객체를 처리하는 작업(객체의 finalize()
작업)이 이루어진 후에 GC 알고리즘에 따라 할당된 메모리를 회수한다.
GC 대상 여부를 결정하는 부분에 관여하는 softly reachable, weakly reachable과는 달리, phantomly reachable은 finalize()
와 메모리 회수 사이에 관여한다. PhantomReference로 참조되는 객체는 finalize()
된 후에 phantomly reachable로 간주된다. 즉, 객체에 대한 참조가 PhantomReference만 남게되면 해당 객체는 바로 finalize()
된다.
GC가 객체를 처리하는 순서는 다음과 같다.
- soft references
- weak references
- 파이널라이즈
- phantom references
- 메모리 회수
PhantomReference의 get()
메서드는 SoftReference, WeakReference와 달리 항상 null
을 반환한다. 따라서 한 번 phantomly reachable로 판명된 객체는 더 이상 사용될 수 없게 된다. 그리고 phantomly reachable로 판명된 객체에 대한 참조를 GC가 자동으로 null
로 설정하지 않으므로, 후처리 작업 후에 사용자 코드에서 명시적으로 clear()
를 실행하여 null
로 설정해야 메모리 회수가 진행된다.
참고
'개발' 카테고리의 다른 글
[JUnit 5] JUnit 5 - 2 (0) | 2020.12.28 |
---|---|
[JUnit 5] JUnit 5 - 1 (0) | 2020.12.27 |
[Java] Garbage Collection (0) | 2020.10.15 |
[UML] Class Diagram (0) | 2020.06.22 |
[Java] String 메모리 관리 (0) | 2020.05.08 |