article thumbnail image
Published 2022. 12. 20. 23:06

GC가 필요한 이유

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

동적으로 할당한 메모리 영역 : heap 영역

필요 없게된 영역 : 어떤 변수도 가리키고 있지 않은 영역

이러한 메모리를 제대로 해제하지 않으면 Memory Leak(필요하지 않은 메모리를 점유하고 있는 현상) 이 발생하다.

자바에서는 이를 자동으로 관리해주어 메모리 누수를 방지한다.

 

장점 

  • 메모리 누수 방지
  • 해제한 메모리에 접근 방지
  • 해제한 메모리를 다시 해제하는 것을 방지

단점 

GC 작업은 순수 오버헤드(어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 / 메모리 ) 작업이다. 

즉, 메모리 해제 대상을 검사하고 해제하는 것은 프로그램이 자신의 일을 하지 못하도록 방해하는 요소이다. 

또한 GC의 메모리 타임을 개발자가 잘 파악하기 어렵다. 자바에서 이를 자동으로 관리해준다고 한들, 완벽하다고 말할 수 없는 요소가 많다. 

그래서 실시간성이 중요한 프로그램의 경우 GC에게 메모리 관리를 맡기기 어려울 수 있다. 

 

GC가 해제 해야할 동적 메모리를 알아서 판단하는 방법

 

 

1.Reference Counting 

heap영역에 선언된 객체들이 각각 reference count라는 숫자를 가지고 있다. 

이 숫자의 의미는 몇가지 방법으로 해당 객체에 접근할 수 있는 지 경우의 수를 의미한다.

만약에 이 reference count 값이 0 이면 GC의 대상이 되는 것이다. 

하지만 이 Reference counting에는 한계가 있다.

순환 참조 문제 

Rootspace 에서 heap space 로 접근이 어려운 경우

서로가 서로를 참조하여 Reference count가 1로 유지된다. 그래서 메모리가 해제되지 못해 Memory Leak이 발생한다. 

 

 

2.Mark and Sweep

Mark  and Sweep은 순환 참조 문제를 해결할 수 있다. 객체의 연결성을 파악해 끊어진 객체를 삭제한다.

객체들은 reachable, unreachable로 나누고 분류되지 않은 나머지는 정리한다. 

여기서 정리하는 과정을 compaction이라고 한다. 필수는 아니지만 메모리 파편화를 막는 역할을 한다.

메모리 파편화란, 메모리 공간이 작게 나누어져 사용한 메모리 공간이 충분하지만 사용하지 못하는 상태를 의미한다.

이를 통해서 Root space로부터 연결이 끊긴 순환참조 되는 객체들은 모두 지울 수 있다. Java와 JS가 이런 방식으로 정리한다.

 

하지만 이러한 Mark and Sweep도 단점이 있다.

우선, 의도적으로 GC를 실행해야 하며, 어플리케이션 실행과 병행이 되어야 한다. 그렇게 되면 앞서 GC의 단점에서 설명해뜻 실행중인 어플리케이션은 GC에게 컴퓨터 리소스를 내줘야 한다. 

 

GC의 실행

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kbh3983&logNo=220967456151

Young Generation

eden : 새롭게 생성된 객체들이 저장되는 영역

servival 영역 : 0,1로 구분된 영역 둘중 하나는 꼭 비워야 한다는 규칙이 있다.

 

초기상태는 객체들이 모두 age-bit 0으로 eden에서 생성된다.

새로운 객체가 계속 생성되다 보면 에덴 영역이 가득 차서 Minor Garbage Collecting이 진행된다.

Reachable한 객체들을 통해 servival 0 영역 으로 이동하고, 숫자는 1 증가한다. 

이 age-bit는 Minor GC때 마다 1씩 더 증가한다.

 

시간이 흘러 eden이 차서 Minor GC가 발생한다. 이후에는

eden에서 살아남은 것들과 기존 servival 0 영역에 있든 것들이 모두 servival1로 이동한다.

그러면 age-bit 1, 2인 것들이 남는다. 

 

이 과정을 반복해 일정한 age-bit이 되면 Old Generation으로 이동한다. (Promotion)

자바 8 기준, Parallel GC를 사용하는 경우 age-bit 15가 되면 이동한다.

 

Old Generation

Old Generation의 영역이 가득 차면 Major GC를 통해서 정리를 진행한다. 

Major GC는 Minor GC보다 비교적 시간이 더 오래 소요된다.

 

이러한 방식으로 GC 구조를 나눈 이유는 대부분의 객체 수명이 짧기 때문이다. 

그래서 앞선 단계에서 정리를 빈번하게 하도록 관리하는 것이다.

어플리케이션 실행과 gc 실행이 병행

 

GC 버전 종류

stop the world

GC를 실행하기 위해 JVM이 어플리케이션 실행을 멈추는 것. 이 시간을 최소화하는 것이 시간 최적화에 도움이 된다.

 

 

Serial GC

하나의 쓰레드로 GC를 실행한다. (stop the world가 길다.. 싱글 쓰레드 환경 및 힙이 작을 때 사용)

 

Parallel GC

여러 쓰레드로 GC를 실행한다. 멀티코어 환경에서 사용한다 (Java 8 의 default 방식, 어플리케이션 속도를 향상시키기 위해 사용한다. )

 

CMS GC(Component mark and sweep) 

stop the world를 최소화하기 위해 사용한다. 대부분의 가비지 수집 작업을 어플리케이션 쓰레드와 동시에 수행한다.

하지만 메모리와 CPU를 많이 사용하고 compaction을 기본적으로 제공하지 않는 단점이 있다. 

 

 

G1 GC(가비지 퍼스트)

heap영역을 조금 다르게 사용한다. heap을 일정 크기의 region을 나누어 young generation, old generation으로 분류한다.

런타임에 G1 GC가 영역별 필요 개수에 따라 영역 region의 개수를 유동적으로 튜닝한다. 

마찬가지로 stop the world 시간을 최소화한다.(Java 9부터 사용)

 

튜닝 맛보기 

성능 개선의 최종 단계

 

객체 생성 자체를 줄이는 노력이 더 필요하다

old generation을 넘어가는 객체 최소화하기

major gc 시간을 짧게 유지하기

 

Young generation과 Old generation을 얼마만큼 할당하는 것이 적당한지를 판단하는 것이 중요하다.

이는 어플리케이션 구조 및 특성에 따라 맞추어 판단해야 한다. 

 

명령어

jstat -gcutil : jvm을 모니터링 할 수 잇다.

jstat - gccapacity : 프로세스가 heap영역을 얼마나 사용중인지 정확한 수치를 파악할 수 있다. 

 

GC를 알아야 하는 이유

Memory leak으로 인해 발생하는 서비스 지연, 즉, 장애에 대한 대응 경험이 요구되는 부분이다.

Heapdump에서 증가하는 영역을 파악하고 원인을 탐색할 수 있다. 

어플리케이션 성능 모니터링 시스템에 대한 사용 경험이 있으면 좋다.(스카우터, Jennifer 오픈소스)

주로 JVM이나 WAS와 DB간에서 잘생하는 응답 시간을 모니터링 한다. 

 

 

 

 

출처 : 우테코 유튜브, 널널한 개발자 유튜브

이미지 출처 : https://mangkyu.tistory.com/119

https://always-kimkim.tistory.com/entry/reading-everyday-9

'CS' 카테고리의 다른 글

OSI 7 layer  (2) 2023.01.25
HTTP 버전  (0) 2022.12.21
TCP / IP 4계층에 대해 알아보기  (0) 2022.11.23
운영체제 구조와 원리  (1) 2022.09.26
인터넷이란? 웹이란? DNS란? 웹서버란?  (0) 2022.09.21
복사했습니다!