Java Garbage Collector 와 Reference

hj·2021년 9월 26일
0

GC (Garbeage Collector)

Java 개발자라면 GC의 역할에 및 해당 내용에 대해서도 대부분 알 것이라 생각된다.
그래도 한번 다시 한번 정리하는 차원에서 글을 적도록 하겠다.

GC 대상 여부

Java의 최상위 클래스는 java.lang.Object 클래스이다.
Object 클래스를 문서를 확인 해보면 finalize() 라는 메소드가 존재한다.
해당 메소드 설명을 보면 객체에 대한 참조가 더 이상 없다고 결정되면 GC에 의해 호출된다고 적혀있다.

그럼 참조가 없다라는 것은 어떻게 판단할까?

오라클 내 문서를 확인해보면 reachable 객체를 제외한 객체를 garbeage라 판단하고 있다.

먼저 reachable 객체와 제외한 객체(reachable의 반댓말인 unreachable 객체라 부르겠다)를 어떻게 판단하는지 알아보자.

모든 객체는 여러 다른 객체들끼리 참조할 수 있다.
이런 상황에서 유효한 참조여부를 파악하려면 항상 유요한 최초 참조가 있어야 하며 이 객체를 root set이라고 한다.

아래 JVM에서 메모리 영역인 런타임 데이터 영역(runtime data area)의 구조를 그리면 다음과 같다.

런타임 데이터 영역은 위와 같이 스레드가 차지하는 영역들과, 객체를 생성 및 보관하는 하나의 큰 힙, 클래스 정보가 차지하는 영역인 메서드 영역, 크게 세 부분으로 나눌 수 있다.

힙에 있는 객체들에 대한 참조는 다음 4가지 종류 중 하나이다.

1. 힙 내의 다른 객체에 의한 참조
2. Java 스택, 즉 Java 메서드 실행 시에 사용하는 지역 변수와 파라미터들에 의한 참조
3. 네이티브 스택, 즉 JNI(Java Native Interface)에 의해 생성된 객체에 대한 참조
4. 메서드 영역의 정적 변수에 의한 참조

이들 중 1번을 제외한 나머지 3개가 root set이다.

아래 그림은 root set과 heap내의 reachable, unreachable 객체 상태를 나타낸 그림이다.

그림에서 보듯이 root set으로부터 참조를 받거나 해당 객체의 참조 사슬에 속한 객체들을 reachable 객체라 판단한다.
즉 reachable 객체를 제외한 객체를 참조가 없다라 판단하는 것이다.

위 그림에서 reachable 객체들은 보통 strongly reachable 객체들이라 부른다.

Reference

java.lang.ref 패키지는 JDK는 1.2버전부터 제한적으로 GC와 상호작용 할 수 있도록 지원하는 패키지이다.
해당문서를 확인해보면 Reachability에 대해 5가지로 나누어 얘기하고 이를 제공하는 클래스는 SoftReference, WeakReference, PhantomReference로 3가지이다.

  • strongly reachable (Strong Reference)
    위에서 언급한 reachable 객체에 해당되며 객체 사이에 어떠한 Reference Object가 없는 객체를 말한다.
    Strong Reference라도 부르며 unreachable 상태일 경우에 GC에서 처리된다.
   Sample sample = new Sample();
   sample = null;

sample 객체를 null로 할당하여 unreachable 객체로 만든다.

  • softly reachable (SoftReference)
    strongly reachable가 아닌 객체 중 오직 SoftReference만 통과하는 참조 사슬이 하나라도 있는 객체를 말한다.
    SoftReference는 GC가 동작할때 마다 회수되지 않으며 GC알고리즘에 의하여 메모리가 부족(OutOfMemonry가 발생되기 전)하다고 판단되거나 참조 된 후 일정시간이 지났을 경우 회수 대상이 된다.
    (회수 대상이라고 즉각적으로 바로 회수되는건 아니며 GC 알고리즘에 따라 다르다)

    문서를 보면 참조시간은 JVM 옵션을 통해 조절 할 수 있다.
    -XX:SoftRefLRUPolicyMSPerMB=value (기본값은 1000)
메모리관리가 잘 되며 충분한 환경속에서 캐시 등을 구현할때 유용하게 사용된다.
Sample sample = new Sample();
SoftReference<Sample> sr = new SoftReference<>(sample);
sample=null;
sample은 null을 대입해 오직 SoftReference내부에서만 참조된 상태를 만드는데 이 상태를 softly reachable 객체라 부른다.
  • weakly reachable (WeakReference)
    strongly reachable, softly reachable가 아닌 객체 중 오직 WeakReference만 통과하는 참조 사슬이 하나라도 있는 객체를 말한다.
    WeakReference는 weakly reachable 객체가 되면 GC가 동작할때마다 항상 GC 메모리 회수 대상이 된다.
    (회수 대상이라고 즉각적으로 바로 회수되는건 아니며 GC 알고리즘에 따라 다르다)

    간단한 캐시나 canonicalizing mappings을 구현 할때 사용을 하며 보통 WeakHashMap를 활용해서 구현한다.
    weakly reachable 객체 생성 코드는 SoftReference->WeakReference 변경된 것 외엔 다른 부분은 위 softly reachable랑 같기에 생략한다.

  • phantom reachable
    strongly reachable, softly reachable, weakly reachable 객체에 모두 해당되지 않는 객체, 이 객체는 finalize() 되었지만 메모리가 아직 회수되지 않은 객체이다.
    위 SoftReference, WeakReference는 GC 대상 객체를 찾는 작업에 관여할 수 있었다면 PhantomReference는 메모리를 회수하는 것에 관여한다.

GC 객체 처리 순서

PhantomReference는 get() 메서드를 호출하면 항상 null을 반환하며 ReferenceQueue가 필수적으로 필요하다.
phantomly reachable 객체가 되면 명시적으로 clear() 메서드를 실행해야 메모리 회수가 진행된다.
객체가 GC에 의해 소거(finalize())당할 때, 후처리 작업이 필요할 경우 사용된다.

	ReferenceQueue<Sample> referenceQueue = new ReferenceQueue<>();
        Sample sample = new Sample();
        PhantomReference<Sample> phantomReference = new PhantomReference<>(sample, referenceQueue);
        sample = null;
        
        ....
        
        if(phantomReference.isEnqueued()) // after process..
        phantomReference.clear();
  • unreachable
    reachable 객체들을 제외한 객체

이러한 것들을 활용해 java.lang.ref 패키지를 활용해 GC가 대상 여부를 판별할때 사용자 코드가 개입할 수 있게 되었다.

다음 글에는 GC 대표적인 알고리즘에 대한 내용을 담도록 하겠다.

* 참고자료

profile
Something Interesting

0개의 댓글