인생을 코딩하다.

[Java] Garbage collection (1) 본문

Java

[Java] Garbage collection (1)

Hyung1 2020. 9. 12. 12:09
728x90
반응형

 

GC에 관해 공부한 걸...기록하기!

 

자바에서는 JVM이 구성되어진 JRE가 제공되며 JVM에 구성되어 있는 가비지컬렉션이 자동으로 사용하지 않는 객체를 파괴시켜 준다. 보통 파괴하는 과정은 힙(heap)내의 객체 중 Garbage를 찾아낸 후 Garbage 객체를 반환하여 메모리를 회수한다. 또 다르게 말하자면,

  • 마킹작업 (사용중인 메모리와 사용 하지 않는 메모리를 식별)
  • 일반 삭제 (참조되지 않는 객체를 제거하고 빈 공간에 대한 포인터를 남겨둠 ) + 압축삭제 (삭제 된 객체와 객체 외 나머지 객체를 메모리 공간으로 효율적으로 사용하며 삭제)

그리고 JVM에 가비지 컬렉션은 객체를을 세대로 나누어 처리한다.

젊은 세대

- 새로운 객체들을 할당, 가득차면 가비지 컬렉션을 매우 빠른속도로 진행, 가벼운 가비지 컬렉션이 수행됨.

이전 세대

- 오래 생존한 객체들을 저장하고, 젊은 세대에서 생성된 객체에 임계 값을 주고 어느정도 연령에 도달하면 다시 이전 세대로 이동. 이전 세대의 객체를 수집하는 것이 가비지 컬렉션이라고도 함.

 

세대별 가비지 컬렉션을 간단히 말하자면,

1. 새로운 객체는 에덴(Eden) 공간에 할당되며, 그 외 두 개의 생존 공간이 모두 비어있는 상태이다.

2. 에덴 공간이 가득차게 되면 사소한(가벼운) 가비지 컬렉션이 시작돤다.

3. 참조된 객체는 첫번째 생존 공간으로 이동되며 참조되지 않는 객체는 모두 삭제된다.

4. 가비지 컬렉션이 수행되는 동안 첫번째 생존 공간의 객체들은 특정 임계값이 넘어가면 두번째 생존 공간으로 이동한다.

5. 두 번째 생존 공간의 객체들도 특정 임계값이 넘어가면 이전 세대로 넘어가게 된다.

6. 이전 세대의 객체가 일정 크기 이상 수집되면 주요 가비지 컬렉션이 수행된다.

 

그림으로 동작 및 상호작용 과정을 자세히 표현하자면,

새로운 오브젝트가 들어오면 Eden Space에 할당

 

 

 

Eden space가 가득면, minor garbage collection이 시작

 

참조되는 오브젝트들은 첫 번째 survivor(S0)로 이동되어지고, 비 참조 객체는 Eden space가 clear 될 때 반환

 

다음 minor GC 때, Eden space에서는 같은 일이 일어남. 비 참조 객체는 삭제되고 참조 객체는 survivor space로 이동. 하지만 이 케이스에서 참조 객체는 두 번째 survivor space로 이동하게 된다. 게다가 최근 minor GC에서 첫 번째 survivor space로 이동된 객체들도 age가 증가하고 S1 공간으로 이동하게 됨. 한번 모든 surviving 객체들이 S1으로 이동하게 되면 S0와 Eden 공간은 Clear 됨.. 주의해야할 점은 이제 우리는 다른 aged 객체들을 서바이버 공간에 가지게 되었다는 것.

 

minor GC 때, 같은 과정이 반복 됨. 하지만 이 번엔 survivor space들은 switch 된다. 참조되는 객체들은 S0로 이동하고 살아남은 객체들은 aged된다. 그리고 Eden과 S1 공간은 Clear 됨..

 

promotion에 대한 그림.. minor GC 후 aged 오브젝트들이 일정한 age threshold(문지방)을 넘게 되면 그들은 young generation에서 old로 promotion 되어진다.

 

minor GC가 계속되고 계속해서 객체들이 Old Generation으로 이동된다.

 

 

전체 과정을 보여주는 그림. 결국 major GC가 old Generation에 시행되고, old Generation은 Clear 되고, 공간이 Compact 되어진다.

 

세대적 GC는 다음 두 가정하에 만들어졌다,

  • 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
  • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.

위의 경험으로부터 퍼포먼스를 향상시켰다. 힙을 작은 파트(세대)로 나눈 것 이다. 그 파트의 이름은 Young, Old or Tenured, Permanent Generation으로 나누었다.

 

1) Young 영역

새롭게 생성한 객체의 대부분이 여기에 위치한다. 가득차게 되면 minor garbage collection이 일어난다.. 대부분 객체가 금방 사라지기 때문에 많은 객체가 이 곳에서 사라진다.

 

2) Old 영역

접근 불가능 상태가 되지 않고 Young 영역에서 살아남은 객체들이 복사된다. Young 영역 보다 크기가 크게 할당하고 큰 만큼 GC는 적게 발생합니다. 이 영역에서 객체가 사라질때 Major GC라고 한다.

 

3) Permanet 영역

Method Area라고도 한다. JVM이 클래스들과 메소드들을 설명하기 위해 필요한 메타데이터들을 포함하고 있다..

 

가비지 컬렉션의 대상이 되는 객체들은 어떤 객체들일까요?

모든 객체의 참조가 모두 null일 경우 가비지컬렉션의 대상이 된다.. 하지만 원형참조(A가 B를 B가 A를 참조하는 형태)인 경우에는 참조로 간주하지 않는다. 객체 A, B에 다른 살아있는 객체의 참조가 없다면 또한 가비지컬렉션의 대상이다.

 

일반적으로는

- 모든 객체 참조가 null인 경우 (Object = null)

- 객체가 블럭 안에서 생성되고 블럭이 종료된 경우

- 부모 객체가 null이면, 자식 객체는 자동적으로 GC 대상이 됨..

- 객체가 Weak 참조만 가지고 있을 경우

- 객체가 Soft 참조이지만 메모리 부족이 발생한 경우

 

GC와 Reachability

Java GC는 객체가 가비지인지 판별하기 위해서 reachability라는 개념을 사용한다. 어떤 객체에 유효한 참조가 있으면 'reachable'로, 없으면 'unreachable'로 구별하고, unreachable 객체를 가비지로 간주해 GC를 수행한다. 한 객체는 여러 다른 객체를 참조하고, 참조된 다른 객체들도 마찬가지로 또 다른 객체들을 참조할 수 있으므로 객체들은 참조 사슬을 이룬다. 이런 상황에서 유효한 참조 여부를 파악하려면 항상 유효한 최초의 참조가 있어야 하는데 이를 객체 참조의 root set이라고 한다.

 

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

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

 

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

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

이들중 힙 내의 다른 객체에 의한 참조를 제외한 나머지 3개가 root set으로, reachability를 판가름하는 기준이 된다.

 

reachability를 더 자세히 설명하기 위해 root set과 힙 내의 객체를 중심으로 다시 그리면 다음과 같다.

 

위 그림에서 보듯, root set으로부터 시작한 참조 사슬에 속한 객체들은 reachable 객체이고, 이 참조 사슬과 무관한 객체들이 unreachable 객체로 GC 대상이다. 오른쪽 아래 객체처럼 reachable 객체를 참조하더라도, 다른 reachable 객체가 이 객체를 참조하지 않는다면 이 객체는 unreachable 객체이다.

 

이 그림에서 참조는 모두 java.lang.ref 패키지를 사용하지 않은 일반적인 참조이며, 이를 흔히 strong reference라 부른다.

 

java.lang.ref는 soft reference와 weak reference, phantom reference를 클래스 형태로 제공한다. 예를 들면, java.lang.ref.WeakReference 클래스는 참조 대상인 객체를 캡슐화(encapsulate)한 WeakReference 객체를 생성한다. 이렇게 생성된 WeakReference 객체는 다른 객체와 달리 Java GC가 특별하게 취급한다. 캡슐화된 내부 객체는 weak reference에 의해 참조된다.

WeakReference<Sample> wr = new WeakReference<Sample>( new Sample());  
Sample ex = wr.get();  
...
ex = null;

위 코드의 첫 번째 줄에서 생성한 WeakReference 클래스의 객체는 new() 메서드로 생성된 Sample 객체를 캡슐화한 객체이다. 참조된 Sample 객체는 두 번째 줄에서 get() 메서드를 통해 다른 참조에 대입된다. 이 시점에서는 WeakReference 객체 내의 참조와 ex 참조, 두 개의 참조가 처음 생성한 Sample 객체를 가리킨다.

위 코드의 마지막 줄에서 ex 참조에 null을 대입하면 처음 생성한 Sample 객체는 오직 WeakReference 내부에서만 참조된다. 이 상태의 객체를 weakly reachable 객체라고 한다.

GC가 동작하여 어떤 객체를 weakly reachable 객체로 판명하면, GC는 WeakReference 객체에 있는 weakly reachable 객체에 대한 참조를 null로 설정한다. 이에 따라 weakly reachable 객체는 unreachable 객체와 마찬가지 상태가 되고, 가비지로 판명된 다른 객체들과 함께 메모리 회수 대상이 된다.

 

정리

WeakReference 클래스는 GC와 밀접한 연광성이있다. GC는 개발자 영역이 아닌데 WeakReference를 사용함으로써 GC에게 어느정도 개입을 할 수가 있다. 특정 객체가 Wear Reference 상태가 되면 GC는 이 객체를 제거한다. 빠르게 객체를 제거함으로써 잠깐 사용하고 제거를 할 수 있다. new를 사용하여 객체를 만들때는 strong reference가 적용이 되는데, WeakReference를 사용하여 객체를 만들 떄는 weak Reference가 적용이 된다.

 

 

객체를 가비지컬렉션의 대상으로 만드는 법 클릭

 

출처 : 

itmining.tistory.com/24 / IT마이닝

d2.naver.com/helloworld/329631 / Naver D2

 

 

728x90
반응형

'Java' 카테고리의 다른 글

[Java] 자바8 Optional 기초  (0) 2020.10.13
[Java] 자바8 스트림(Stream)  (2) 2020.10.07
[Java] 자바8 람다식 기초  (0) 2020.10.07
[Java] 재귀호출 구현 연습 및 코드 설명  (0) 2020.09.12
[Java] Garbage collection (2)  (0) 2020.09.12
Comments