제리의 배움 기록
[Java] Reference Type : 참조유형 본문
자바는 효율적은 GC를 위해 4가지의 참조유형을 다룹니다.
적절한 Reference를 사용하면 GC 대상에 우선순위를 적용하여 메모리를 효율적으로 관리할 수 있습니다.
자바의 참조유형
- Strong Reference : 일반적인 기본 참조 유형
- Soft Reference
- Weak Reference
- Phantom Reference
SoftReference, WeakReference, PhantomReference 3가지 클래스에 의해 생성된 객체를 reference object 라고 합니다.
하나의 객체는 여러 reference 조합으로 참조될 수 있습니다. reference 타입 구분은 root set으로 부터를 기준으로 합니다.
- strongly reachable: root set으로부터 시작해서 객체까지 도달하는 여러 참조 사슬 중 reference object가 아닌 참조가 하나라도 있는 객체
- softly reachable: strongly reachable 이 아닌 객체 중에서(Strong Reference가 없는) weak reference, phantom reference 없이 soft reference만 통과하는 참조 사슬이 하나라도 있는 객체
- weakly reachable: strongly reachable, softly reachable이 아닌 객체 중에서, phantom reference 없이 weak reference만 통과하는 참조가 하나라도 있는 객체
- phantomly reachable: strongly reachable, softly reachable, weakly reachable 모두 해당되지 않는 객체. 이 객체는 파이널라이즈(finalize)되었지만 아직 메모리가 회수되지 않은 상태
- unreachable: root set으로부터 시작되는 참조 사슬로 참조되지 않는 객체
GC 과정
GC 대상 객체를 찾는 작업 -> GC 대상 객체를 처리(파이널라이즈) -> 할당된 메모리를 회수
연속된 작업은 아님
GC가 객체를 처리하는 순서
- soft references
- weak references
- 파이널라이즈
- phantom reference
- 메모리회수
ReferenceQueue
어떤 객체가 더 이상 필요없게 되었을 때 관련 후처리를 해야할 경우 유용하게 사용할 수 있음
Soft Reference
- as late as possible : 메모리 여유가 충분하다면 GC가 수행되더라고 수거되지 않습니다.
- 객체 생성시 RefereceQueue를 생성자 인자로 넘기냐에 따라 사용유무가 정해집니다.
- 객체 내부의 참조가 null로 설정된 후 ReferenceQueue에 enqueue
- => 이 과정은 GC에 의해 자동으로 수행됨
MyClass ref = new MyClass();
SoftReference<MyClass> softRef = new SoftReference<MyClass>(ref);
// 이 시점에 GC의 실행 대상이 가능
ref = null;
// JVM의 메모리가 부족하지 않아 GC 실행 대상이 되지 않은 경우 null이 반환되지 않고 기존 객체가 반환됨
ref = softRef.get();
Weak Reference
- GC가 수행될때마다 회수 대상 (실제 GC 알고리즘에 따라 반드시 회수된다고 보장할 수 없음)
- 짧은 주기에 자주 사용되는 객체를 캐시할 때 유용
- 객체 생성시 RefereceQueue를 생성자 인자로 넘기냐에 따라 사용유무가 정해집니다.
- 객체 내부의 참조가 null로 설정된 후 ReferenceQueue에 enqueue
- => 이 과정은 GC에 의해 자동으로 수행됨
MyClass ref = new MyClass();
WeakReference<MyClass> weakRef = new WeakReference<MyClass>(ref);
// 이 시점에 GC의 실행 대상이 가능
ref = null;
// 다음 GC 실행시 힙 메모리에서 제거 제거된 경우 null 반환
ref = weakRef.get();
Phantom Reference
- 객체 내부의 참조를 null로 설정하지 않고 참조된 객체를 phantomly reachable 객체로 만든 이후에 ReferenceQueue에 enqueue
- 객체에 대한 참조가 PhantomReference만 남게 되면 해당 객체는 바로 파이널라이즈
- 파이널라이즈 된 이후에 phantomly reachable로 간주하여 ReferenceQueue에 enqueue
- 파이널라이즈 이후 작업을 애플리케이션이 수행하게 하고 메모리 회수는 지연
- PhantomReference는 반드시 ReferenceQueue를 사용해야함.
=> 이를 통해 객체의 파이널라이즈 이후 필요한 작업들을 처리 - phantomly reachable 객체는 PhantomeReference get() 매소드에서 항상 null을 반환 하므로 더이상 사용할 수 없음
- 객체에 대한 참조를 GC가 자동으로 null로 설정하지 않으므로 후처리 작업 후 사용자 코드에서 명시적으로 clear() 매소드를 실행하여 null로 설정해야 메모리 회수가 진행됨
@Test
public void test() {
MyClass ref = new MyClass();
ReferenceQueue<MyClass> refQueue = new ReferenceQueue<MyClass>();
PhantomReference<MyClass> phantomRef = null;
// 팬텀 참조는 ReferenceQueue를 반드시 사용해야함
phantomRef = new PhantomReference<MyClass>(ref,refQueue);
ref = null;
System.gc();
System.out.println(phantomRef.isEnqueued());
System.out.println(phantomRef.get()); // null
}
[참고]
'자바' 카테고리의 다른 글
[Java] eqauls와 hashcode (0) | 2021.11.12 |
---|---|
[Java] 2차원 배열은 어떻게 메모리에 저장될까? (0) | 2021.11.12 |
[Java] 생성자와 초기화 블럭 실행 순서 (0) | 2021.11.12 |
[Java] float와 double 연산이 제대로 되지 않는 이유 (0) | 2021.11.12 |
[Java] 메서드 시그니처 (0) | 2021.11.12 |
Comments