2 minute read

★Java Application은 c나 c++처럼 동적으로 할당한 메모리를 수동으로 해제하지 않는다. GC라는 매커니즘을 통해 자동으로 메모리 해제 프로세스를 수행하므로 수동으로 해서도 안된다.

★자바의 객체는 Heap에 저장되어 메모리를 점유하고 있는데, 더 이상 필요하지 않는 객체는 제거되지 않으면 메모리 공간을 낭비하고, Application의 성능에 심각한 제약을 준다. 이런 필요없는 객체(Garbage)를 제거하는 작업을 GC(Garbage Collection)이라고 한다. 따라서 GC는 JVM의 Runtime Data Area의 Heap, Method Area, Call Stack중 Heap에서 동작하게 된다.

★많은 GC알고리즘이 있지만 공통적으로 두 가지 작업을 수행한다.

  1. Heap 내부의 Garbage가 아닌 객체를 탐색한다.
  2. 찾아 낸 Garbage가 아닌 객체를 제외한 객체들의 메모리를 회수한다.

★Heap에 존재하는 객체를 Stack의 어떠한 참조변수도 참조하지 않을 때 이 객체는 Unreachable Object, 또는 Garbage라고 한다.

★stop the world : JVM이 GC를 수행할 때 현재 실행중인 GC Thread를 제외한 모든 Thread를 일시중지 시키는 것을 말한다. 따라서 대부분의 GC최적화 작업은 stop the world의 시간을 최소화 하는 방향으로 진행된다. System.gc()로 자바 코드에서 강제로 메모리 해제 작업을 진행할 수 있으나, 이 메소드를 실행 하면 stop the world가 발생하여 심각한 성능저하가 발생하므로 위에서 말한 대로 수동으로 해서는 안된다. 하지만 Garbage Collection을 유도하기 위해 어떤 객체의 참조를 null로 지정하는 경우는 많이 있다.

★JVM의 Heap은 Young, Old, Perm(JDK8 이후로는 Metaspace영역으로 대체 되었다고 하는데, 네이티브 메모리 영역이므로 Heap에서 빠지게 되었다. JDK8이전에도 Perm영역은 잘 사용하지 않았다고 한다.)으로 구성되어 있다. GC는 주로 Young, Old영역을 다룬다.

★Minor GC : Young영역은 Eden영역과, 2개의 Survivor영역, 합쳐서 3개의 영역으로 구성되어 있다. 처음 생성되는 객체는 Eden영역에 들어가는데, Eden영역이 꽉 차거나 어느정도 쌓이게 되면 GC가 발생한다. 이 때 Unreachable 객체는 삭제되고, 살아남은 객체는 하나의 Survivor영역으로 옮겨진다. 이후 또 GC가 발생하면 Eden과 이전 GC에서 객체들이 옮겨간 Survivor영역에서 살아남은 객체들이 비어있던 또 다른 Survivor영역으로 이동한다. 이러한 과정에 의해 두 Survivor영역 중 한 영역은 항상 비어있는 상태가 된다. Survivor에서 또 다른 Survivor로 옮겨진 객체들은 age값이 증가되며 옮겨진다. 이렇게 Young 영역에서 일어나는 GC를 Minor GC라고 한다.

★Promotion : Surivor를 전전하며 age를 키워온 생존 객체들은 age가 특정 값 이상이 되면 Old영역으로 이동하는데 이를 Promotion이라고 한다.

★Major GC : Promotion작업이 반복해서 일어나 Old영역이 가득 차게 되면 Old영역에서도 GC를 수행하게 되는데 이를 Major GC라고 한다. 이런 Minor GC, Promotion, Major GC가 반복되며 GC가 수행된다. (Major GC와 Minor GC를 모두 수행하는 작업을 Full GC라고 한다.)

★5가지 GC방식 간단 정리

  1. Serial Collector(직렬 콜렉터) : Old영역에 있는 객체들을 Mark-Sweep-Compact알고리즘으로 처리하는 방식이다. Mark(식별)하고 Sweep(제거)한 후 Compact(압축)하는 방식인데 쉽게 얘기해 쓸데없는 물건을 버리고 남아있는 물건을 시작위치부터 차곡차곡 정리하는 방식이다. 이 과정을 하나의 Thread에서 진행하는데, 이 때문에 수행 속도가 느릴 수 있으므로 주로 대기시간이 그렇게 많지 않은 클라이언트 장비에서 주로 사용한다.

  2. Parallel Collector(병렬 콜렉터, Throughput GC) : 기본 알고리즘은 Serial Collector와 같으나 여러개의 Thread에서 수행한다는 점이 다르기 때문에 Serial Collector보다 빠르다. 이 때 Garbage Collector는 기본적으로 CPU갯수 만큼의 Thread가 GC를 수행한다.

  3. Parallel Old Collector : Young영역에서의 알고리즘은 Parallel Collector와 동일하나 Old영역에서의 처리과정이 다르다. Mark-Sweep-Compaction대신 Mark-Summary-Compaction 단계를 거친다. Summary단계는 이전에 GC를 수행한 영역에 살아있는 객체의 위치를 조사하는 단계이다.

  4. Concurrent Mark Sweep Collector(CMS Collector) : Young영역에 대한 GC는 Parallel GC와 같고, Old는 Initial Mark(Class Loader에서 가장 가까운 객체 중 살아있는 객체를 찾는다), Concurrent Mark(위에서 찾은 객체에서 참조하고 있는 객체를 따라가며 확인한다.(다른 Thread와 동시에 진행된다)), Remark(Concurrent Mark단계에서 새로 추가되거나 참조가 끊긴 객체를 확인한다), Concurrent Sweep(정리한다(다른 Thread와 동시에 진행된다))단계를 거친다.

  5. G1 Collector : 메모리를 바둑판 모양으로 나눈 후 각 영역(Region)에 기존의 Eden, Survivor, Old영역의 역할을 동적으로 할당한다. Region의 한 영역이 꽉 차면 GC를 수행하고, 다른 영역에 객체를 할당한다.

Categories:

Updated: