이 글은 PC 버전 TISTORY에 최적화 되어있습니다.
서론
이전에 안드로이드 메모리 관리 관련하여 Strong, Soft, Weak Reference에 대해 알아보면서 GC에 대해 살짝 언급한 적이 있습니다. Java의 가비지 컬렉터는 다양한 종류가 있지만 공통적으로 다음의 2가지 작업을 수행합니다.
1. 힙(Heap) 내의 객체 중 Garbage를 찾아낸다.2. 찾아낸 Garbage 객체를 반환하여 메모리를 회수한다.
최초의 JAVA는 Garbage Collection 작업에 사용자가 관여하지 않도록 구현되었었지만, JDK 1.2 부터는 java.lang.ref 패키지를 통해서 GC와 어느정도 상호작용을 할 수 있도록 해주었습니다. 기존의 Strong reference 뿐 아니라 Soft, Weak, Phantom 3가지의 새로운 참조 방식을 통해 앞서 말했듯이 GC와의 상호작용을 할 수 있게 되었습니다. GC와 Reference, Reachable에 대해서는 NAVER D2에 잘 나와 있으니 보시기 바라고, 오늘은 GC의 동작 과정과 유형에 대해서 알아보도록 하겠습니다.
Garbage Collection의 특징
객체들은 일단 생성되면 위 그림과 같이 힙 영역에 생성됩니다. 힙에 새로운 객체를 생성했을 때 공간이 부족하다면 JVM은 Out of MemoryGC을 뿌리게 됩니다. GC는 위에서 말씀 드렸듯이 Root Set of References(유효한 최초의 참조)가 이루어지지 않는 객체 Unrechable Objects들을 수거한다고 했습니다. GC는 객체를 메모리에서 제거하기 전에 해당 객체의 finalize( ) 메소드를 호출합니다. 이렇게 보면 GC를 자주 호출해주어 불필요한 메모리를 제거해주고 싶지만 안타깝게도 GC는 사용자가 강제로 수행할 수 없습니다. 언제 일어나는지도 정확히 할 수 없죠.
GC 대상이 되는 객체
일반적으로 다음과 같은 경우에 GC의 대상이됩니다.1. 모든 객체 참조가 null 인 경우2. 객체가 블럭 안에서 생성되고 블럭이 종료된 경우3. 부모 객체가 null이 된 경우, 자식 객체는 자동적으로 GC 대상이 된다.4. 객체가 Weak 참조만 가지고 있을 경우5. 객체가 Soft 참조이지만 메모리 부족이 발생한 경우
자동 Garbage Collection?
Step 1 : Marking프로세스는 마킹을 호출합니다. 이것은 GC가 메모리가 사용되는지 아닌지를 찾아냅니다. 참조되는 객체는 파란색으로, 참조되지 않는 객체는 주황색으로 보여집니다. 모든 오브젝트는 마킹 단계에서 결정을 위해 스캔되어집니다. 모든 오브젝트를 스캔하기 때문에 매우 많은 시간을 소모하게 됩니다.Step 2 : Normal Deletion참조되지 않는 객체를 제거하고, 메모리를 반환합니다. 메모리 Allocator는 반환되어 비어진 블럭의 참조 위치를 저장해 두었다고 새로운 오브젝트가 선언되면 할당되도록 합니다.Step 3: Compacting
퍼포먼스를 향상시키기 위해, 참조되지 않는 객체를 제거하고 또한 남은 참조되어지는 객체들을 묶습니다. 이들을 묶음으로서 공간이 생기므로 새로운 메모리 할당 시에 더 쉽고 빠르게 진행 할 수 있습니다.
Generational Gabage Collection?위에 언급했듯이, 모든 객체를 mark & compact하는 JVM은 비효율적입니다. 오브젝트를 할당 할 때마다 GC 시간에 오브젝트들의 리스트를 읽는 시간은 점점 길어질 뿐이죠, 그러나 경험적 분석에 의하면 대두분의 객체는 짧게 생존합니다. 위의 데이터를 보시면 알 수 있습니다. Y축은 할당된 바이트의 수이고 X축은 바이트가 할당될 때의 시간입니다. 보시다시피 시간이 갈수록 적은 객체만이 남습니다.세대적 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이 클래스들과 메소드들을 설명하기 위해 필요한 메타데이터들을 포함하고 있습니다.
Generational Garbage Collection의 과정
1. 먼저, 어떠한 새로운 오브젝트가 들어오면 Eden Space에 할당합니다.
2. Eden space가 가득차게 되면, minor garbage collection이 시작 됩니다.
3. 참조되는 오브젝트들은 첫 번째 survivor(S0)로 이동되어지고, 비 참조 객체는 Eden space가 clear 될 때 반환됩니다.
4. 다음 minor GC 때, Eden space에서는 같은 일이 일어납니다. 비 참조 객체는 삭제되고 참조 객체는 survivor space로 이동하는 것 입니다. 그러나 이 케이스에서 참조 객체는 두 번째 survivor space로 이동하게 됩니다. 게다가 최근 minor GC에서 첫 번째 survivor space로 이동된 객체들도 age가 증가하고 S1 공간으로 이동하게 됩니다. 한번 모든 surviving 객체들이 S1으로 이동하게 되면 S0와 Eden 공간은 Clear 됩니다. 주의해야할 점은 이제 우리는 다른 aged 객체들을 서바이버 공간에 가지게 되었다는 것입니다.
5. 다음 minor GC 때, 같은 과정이 반복 됩니다. 그러나 이 번엔 survivor space들은 switch 됩니다. 참조되는 객체들은 S0로 이동합니다. 살아남은 객체들은 aged되죠. 그리고 Eden과 S1 공간은 Clear 됩니다.
6. 이 그림은 promotion을 보여줍니다. minor GC 후 aged 오브젝트들이 일정한 age threshold(문지방)을 넘게 되면 그들은 young generation에서 old로 promotion 되어집니다. 여기서는 8을 예로 들었습니다.
7. minor GC가 계속되고 계속해서 객체들이 Old Generation으로 이동됩니다.
8. 이 그림은 전 과정을 보여주고 있습니다. 결국 major GC가 old Generation에 시행되고, old Generation은 Clear 되고, 공간이 Compact 되어 집니다.
'Basic > Java' 카테고리의 다른 글
Java Enum 기본 (0) | 2019.11.27 |
---|---|
[JAVA] 객체(Object)의 형 변환 (2) | 2016.07.19 |
[JAVA] Static에 대하여 (0) | 2016.07.19 |
[JAVA] JVM의 메모리구조 (0) | 2016.07.19 |
[JAVA] 자바의 변수 (클래스 변수, 인스턴스 변수, 지역 변수) (6) | 2016.07.19 |
[JAVA] 절차지향언어와 객체지향언어 (0) | 2016.07.19 |