우아한 테코톡(12), GC(Garbage Collection)

2022. 9. 23. 19:00간단한 컴퓨터 이론/우아한테코톡

728x90
반응형

 

본 포스팅은 우아한Tech의 테코톡 조엘님의 GC 영상을 정리한 내용입니다.

GC의 동작 원리와 알고리즘을 위주로 정리했습니다.


GC(Garbage Collection)

1. GC가 왜 필요한가

1) GC란?

프로그램이 동적으로 할당했던 메모리 영역 중 필요 없게 된 영역을 알아서 해제하는 기법

동적으로 할당한 메모리 영역은 힙 영역을 의미하고, 필요 없게된 영역은 어떤 변수도 가리키지 않는 변수를 의미한다. 이를 제대로 해제하지 않으면 메모리 누수가 발생한다. 자바에서는 GC가 이 역할을 맡아준다.

 

2) GC의 장점

메모리 누수를 막을 수 있고, 해제된 메모리에 접근하거나 해제된 메모리를 또 해제하는 것을 방지할 수 있다.

 

3) GC의 단점

어떤 메모리 영역이 해제의 대상이 될지 검사하고 해제하는 것은 프로그램이 해야하는 일을 방해하는 오버헤드이기도 하고, 개발자는 GC가 메모리를 언제 해제하는지 알기 어렵다. 따라서 실시간성이 강조되는 프로그램은 GC에게 메모리 관리를 맡기는 것이 좋지 않을 수 있다.

 


2. GC 알고리즘

1) Reference Counting

(1) Reference Counting란?

Reference Count는 해당 객체에 접근할 수 있는 방법이 몇 가지 있는지를 가지고 이를 판단한다. 해당 객체에 접근할 수 있는 방법이 없는 경우에는 메모리 영역을 해제한다. 하지만 이러한 Reference count는 순환참조인 경우에는 서로가 서로를 참조하기에 Reference Count가 1이되고, 사용하지 않는 경우에도 메모리 해제를 해주지 않는다는 단점이 있다.

 

cf) Root space: 스택 변수, 전역 변수 등 힙 영역 참조를 담은 변수

2) Mark and Sweep

(1) Mark and Sweep란?

루트에서부터 해당 객체에 접근이 가능하는지를 해제의 기준으로 삼는다. 그래프 순회를 통해 연결된 객체를 찾고(mark), 연결이 끊어진 객체들은 지우는 방식(Sweep)을 통해 GC를 구현할 수 있다. 루트로부터 연결이 되어있다면 Reachable, 연결되지 않았다면 Unreachable이라 부른다. Sweep 이후에는 분산되어있던 메모리가 정리되는데 이는 메모리 파편화를 방지하기 위함으로 이를 Compaction이라 부른다. 

 

 

이처럼 Mark and Sweep 알고리즘을 사용하면 루트로부터 연결이 끊긴 객체는 참조하지 않기에 Reference Counting의 순환참조 문제를 해결할 수 있다. 자바와 자바스크립트가 이를 통해 메모리 관리를 한다.

 

(2) Mark and sweep의 특징

Reference count가 0이 되면 지워버리는 Reference counting과는 달리 의도적으로 GC를 실행시켜야한다.  어느 순간에는 실행시간에 GC에게 컴퓨터 리소스를 내줘야한다. 어플리케이션의 실행과 GC의 실행이 병행되기에 이를 잘 조절하는 것이 중요하다. 

 

 


3. JVM의 GC

1) JVM의 구조

JVM은 크게 세가지 영역으로 나뉜다.

(1) 클래스 로더

바이트 코드를 읽고 클래스 정보를 메모리의 Heap/Method Area에 저장한다.

 

(2) 메모리

실행 중인 프로그램의 정보가 올라가 있다.

 

(3) 실행 엔진

바이트 코드를 네이티브 코드로 변환시키고 GC를 실행한다.

 

2) JVM 메모리

쓰레드와 관련해 JVM은 두가지 영역으로 나눌 수 있다.

(1) 모든 쓰레드가 공유하는 영역

Method Area, Heap

 

(2) 각 쓰레드마다 공유하게 생성하며 쓰레드 종료시 실행되는 영역

JVM language Stack, PC register, Native Method Stack

 

3) Runtime data areas

(1) Methods Area

프로그램의 클래스 구조를 메타데이터처럼 가지고 메소드의 코드를 저장한다.

 

(2) Heap

실행 중에 생성되는 객체 인스턴스를 관리한다.

 

(3) Stack

- 메소드 호출을 스택 프레임이라는 블록으로 쌓으며, 로컬변수, 중간 연산 결과들이 저장된다.

 

(4) PC Register

쓰레드가 현재 실행할 스택 프레임의 주소를 저장한다.

 

(5) Native Method

C/ C++ 등의 로우 레벨 코드를 실행하는 코드이다.

 

 

4) JVM GC의 Root space

 

5) JVM의 Heap 영역

(1) Young generation

minor GC로 불리고 새롭게 생성되는 객체들이 할당되는 영역인 Eden, minor GC로부터 살아남은 객체들이 존재하는 영역인 Survival 0, survival 1 영역이 있다. survival 영역은 survival 0 또는 1 둘 중 하나는 꼭 비어있어야한다는 규칙이 있다.

 

(2) Old generation

major GC로 불리고 오래된 객체를 모아두는 영역이다.

 

6) JVM GC 실행 방식 살펴보기

회색 네모는 새로운 객체인데 이를 생성하면 에덴 영역이 꽉찬다. 이때 minor GC가 일어난다. 루트로부터 reachable한 객체는 survival 0으로 옮겨진다.

 

이때 minor gc에서 살아남을 때마다 age-bit를 하나씩 증가시킨다.

 

이후 또 minor GC가 발생하면 reachable한 객체는 age-bit를 하나 더 증가시킨 뒤 survival 1로 옮겨진다. 이후 GC가 일어나면 또 다시 survival 0으로 옮긴다.

이후 일정 수준의 age-bit가 넘어가면 오래도록 참조될 객체로 판단하여 Old generation으로 옮긴다.  이 과정을 Promotion이라 한다. Java8에서는 Parallel GC 방식 사용 기준으로 age-bit가 15가 되면 promotion이 된다. 이후 Old generation이 꽉차면 Maajor GC를 통해 Mark and Sweep 방식을 통해 필요 없는 메모리를 비워준다. 이는 minor GC보다 더 많은 시간이 걸린다.

대부분의 객체의 수명이 작기때문에 Young generation 안에서 처리해주도록 하면 비용 효율적으로 동작할 수 있기에 이를 구분한다.

 

7) 어플리케이션 실행과 GC 실행의 병행

(1) Stop The World

GC를 실행하기 위해 JVM이 어플리케이션 실행을 멈추는 것이다. 이를 최소화하는 것이 주요과제이다.

 

 

(2) Serial GC

하나의 쓰레드로 GC를 실행하는 방식으로, Stop the world 시간이 길다.

싱글 쓰레드 환경 및 Heap이 매우 작을 때 사용하는 방식이다.

 

(3) Parallel GC

여러개의 쓰레드로 GC를 실행하기에 Stop the world 시간이 짧아졌다.

멀티코어 환경에서 어플리케이션 처리 속도를 향상시키기 위해 사용된다. 자바 8에서 기본적으로 사용되는 방식이다.

 

(4) CMS GC (Concurrent-Mark-Sweep)

Stop the world 최소화를 위해 고안된 방식으로 GC 작업을 어플리케이션과 동시에 실행된다. 

메모리와 CPU를 많이 사용하고 메모리 파편화를 해결하는 Compaction이 지원되지 않는다는 단점이 있다.

G1 GC 방식이 등장함에 따라 이는 대체되었다.

 

(5) G1 GC (Garbage first)

Heap을 일정 크기의 Region으로 나눠 영역별로 Young, Old generation으로 나눠 활용한다.

런타임에 G1 GC가 필요에 따라 영역별 Region 개수를 튜닝해 Stop the world를 최소화할 수 있게되었다.

Java9 이상부터는 G1 GC를 기본 GC 실행방식으로 사용한다.

 


4. JVM GC 튜닝

성능 개선의 최종 단계로 객체 생성 줄이기위한 코드 단계에서의 최적화가 선행되어야한다. 

 

1) 목표

(1) Old generation으로 넘어가는 객체 최소화하기

(2) Major GC 시간을 짧게 유지하기

 

한정된 Heap 영역에 Young generation이나 Old generation을 얼마나 설정하는지가 중요하다. 이는 어플리케이션 구조 및 특성에 따라 정하는 것이 중요하다. 

 

jdk 설치 시 자동으로 설치되는 jstat의 gcutil 명령어로 GC와 관련된 정보를 모니터링할 수 있다.

jstat gccapacity 명령어를 통해 Heap에 할당된 메모리를 모니터링할 수 있다.

 


출처

https://www.youtube.com/watch?v=FMUpVA0Vvjw 

 

728x90
반응형