일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 파이썬
- PID
- 자바파이썬
- Anaconda
- 클라이언트사이드렌더링
- 카우치코딩 #couchcoding #6주포트폴리오 #6주협업프로젝트v
- 필사
- Morphological analysis #Corpus
- 출처: 자바의 신 8장
- github
- terminate
- #스파르타코딩클럽후기 #내일배움캠프후기
- 플젝후체크
- github markdown
- Technical Writing
- 비동기
- 코딩온라인
- address
- 카우치코딩 #couchcoding #6주포트폴리오 #6주협업프로젝트
- 서버사이드렌더링
- taskkill
- expression statement is not assignment or call html
- SSR
- 모바일웹스킨
- gitbash
- Kakao
- 파이콘
- Machine Learning
- 마크다운
- khaiii
- Today
- Total
개발 일기
자바의 가비지 컬렉션 본문
GC (Garbage Collection) 란?
가비지는 프로그램에서 객체를 할당했지만, 더 이상 참조되지 않는 객체입니다.
가비지들을 제거하는 작업을 가비지 컬렉션(Garbage Collection, 이하 GC) 이라고 해요.
하나의 객체는 메모리를 점유하기 때문에, 쓰지 않는 객체는 메모리 최적화를 위해 해제해주는 거죠.
C언어에도 GC라는 개념이 있습니다. C언어에서는 GC 작업을 개발자가 하는 반면, 자바에서는 JVM 이 메모리 관리를 도맡아 해줘서 개발자가 편합니다.
GC 의 이점?
위의 설명에서 추측할 수 있듯, 메모리 최적화가 됩니다.
그리고 GC 를 많이 할 수록, 서버의 응답시간에 영향을 미치기 때문에 성능 관리에 있어서도 중요합니다.
특히 Full GC 의 경우 속도가 매우 느립니다 (참고로, Major GC는 Full GC일까요? 아래 minor vs major gc 에서 설명하겠습니다)
그리고 GC가 일어날 때는 Stop the world (GC 실행 쓰레드 제외한 쓰레드들이 멈추는 것) 현상이 일어납니다.
순간적으로 자바 어플리케이션이 멈추는 현상이기 때문에, FULL GC의 빈도와 소요 시간은 애플리케이션의 성능과 안정성에 영향이 큽니다. Stop the world 는 pause time 이라고도 불립니다.
GC의 동작
GC의 주체는 가비지 컬렉터입니다. 가비지 컬렉터는 JVM 내부에 위치하고, GC 는 JVM의 런타임 영역중 힙 영역에서 발생합니다 (스택 등 힙 영역 외에는 GC를 안합니다) 힙은 new() 키워드 등 동적으로 생성된 객체와 배열이 저장되는 영역입니다.
가비지 컬렉터의 역할은 다음과 같습니다.
1) 객체 메모리 할당
2) 사용중인 메모리 인식
3) 사용중이지 않은 메모리 인식
왜 Stop the world 가 일어날까
왜 GC 를 할 때 Stop the world 가 일어날까요? garbage collector 가 작동하는 중간에, 새 객체가 할당되거나 기존 객체가 갑자기 unreachable 이 되는 상황을 방지하기 위함입니다. (Wikipedia Stop-the-world vs. incremental vs. concurrent)
collection cycle이 진행되는 동안 프로그램이 다른 일을 할 수 없다는 것은 단점입니다. 하지만 Garbage 가 많다면, 메모리 해제 작업만 해주면 되니 stop the world 로 인한 latency는 크게 문제가 되지 않는다고 합니다 (plumb) 살아남아서 survivor 로 이동하는 객체가 많다면 stop the world 로 멈춰있는 시간이 (pause time) 늘어날 수 있겠죠.
Minor GC vs Major GC
위 그림의 Perm은 java 8 이전에 jvm 에 의해서 크기가 강제되던 영역이었습니다. 이후 MetaSpace 가 등장했는데, 이는 Native Memory 영역이어서 OS 가 자동으로 크기를 조절합니다. 기존과 비교해서 큰 메모리 영역을 사용할 수 있게 되었습니다. Perm 영역 크기로 인한 java.lang.OutOfMemoryError를 보기 어려워지고, 개발자는 영역 크기 확보를 크게 신경쓸 필요가 없습니다 (참고)
Minor GC는 Young 영역에서 일어나고, Major GC는 Old 영역에서 일어납니다. Full GC는 young 과 old 에서 모두 일어나는 GC 를 말하는 데요. 대부분의 Major GC가 Minor GC에 의해서 일어나기 때문에, Major GC가 일어나는 상황은 사실 full GC나 다름없습니다 (참고)
왜 굳이 Old/Young 으로 나누었을까요?
GC는 두 가지 전제조건을 갖고 있는데요
1. 대부분의 객체는 금방 접근 불가능한 상태(unreachable)가 된다. 금방 garbage 가 된다.
2. 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
대부분의 객체는 오래 살지 못하고, Minor GC가 빈번하게 일어나기 때문에 Young 영역과 Old 를 나눈 것입니다.
Mark-Compact-Sweep
GC 의 종류는 Serial, Parallel 등 다양하고 각 알고리즘은 조금씩 차이가 있습니다.
본 글에서는 자세하게 설명하기 보다는, Mark, Delete (Sweep), Compact 행위와 Major/Minor 의 차이를 다루겠습니다.
(1) Mark: GC 가 참조되는 객체와/그렇지 않은 객체를 식별합니다. 모든 객체가 스캔되기 때문에, 많은 시간이 소요되는 과정입니다.
(2) Normal Deletion (Mark-SweepCompact알고리즘의 Sweep 과도 같습니다)
Memory Allocator 는 여유 공간 (free spaces)의 주소를 갖고 있다가, 새로운 할당이 필요할 때 이 공간들을 찾아줍니다.
(3) Compact
참조 되고 있는 객체들을 한쪽에 몰아넣음으로써, 새로 객체가 할당될 메모리를 위한 공간을 만듭니다.
이렇게 하면 새로운 메모리 할당이 훨씬 빠르고 쉬워져서 성능향상에 도움이 됩니다.
GC의 동작은 애니메이션으로 확인하면 이해가 쉽습니다. 우테코 엘리님 GC 발표 3:00 - 5:00 를 보시는 걸 추천드립니다.
Major GC는 위의 Mark-Sweep(Delete)-Compact 과정을 수행합니다.
Minor GC 는 Mark-Sweep-Compact 보다는 Mark-Copy에 가깝습니다. 마이너 GC 에서는 Eden, Survivor0, Survivor1 을 옮겨가면서 작업하고, 옮길 때 Suvivor 한쪽은 완전히 비어있어야 한다는 원칙이 있습니다. 그래서 살아있는 객체만 식별하고, 다른 영역에 복사하기 때문에 Mark& Copy에 가깝습니다. 반면 Major GC는 Old 영역 한 곳에서 발생하기 때문에, 메모리 단편화가 발생할 수 밖에 없고 Compact 작업이 필요합니다.(plumb)
GC 알고리즘
GC 방식은 아래와 같지만, 여기서는 G1GC 에 대해서만 설명하겠습니다. 나머지 4개의 GC 설명은 D2 아티클 을 참조해주세요.
- Serial GC
- Parallel GC
- Parallel Old GC(Parallel Compacting GC)
- Concurrent Mark & Sweep GC(이하 CMS)
- G1(Garbage First) GC
G1GC ( Oracle )
G1GC 는 자바 9 이상부터 Default GC 입니다.
위의 그림에서 힙 영역은 Young(Eden, survivor) 과 Old가 물리적으로 나뉘었습니다. 하지만 G1GC에서는 영역을 나누지 않습니다.
G1은 힙을 일정한 크기의 region 이라는 논리적 단위로 나누어서 관리합니다.G1 GC 는 Garbage만 있는 리전을 처음에 수거하기 때문에, G1이라는 이름이 붙었습니다.
G1GC의 가장 큰 장점은 성능입니다. gc 중에 가장 빠릅니다.
다른 GC 와 비교해보면, Young 과 Old 영역을 한 번에 탐색할 때는 큰 방을 한 번에 훑는다면,
G1GC 는 큰 방을 잘게 쪼개서 쓰레기가 꽉차 있는 부분만 탐색합니다 (마킹 시 할당 리전을 탐색합니다)
그래서 처리 시간, 소요 메모리 등의 오버 헤드가 비교적 적습니다.
참고 자료
공식문서 https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
[책]
자바의 신 2권
자바의 정석 2권
자바 성능 튜닝 이야기.
[영상]
우아한 테크코스 GC 편 - 엘리님 (강추!)
[블로그]
plumb.io
https://d2.naver.com/helloworld/1329
P.S. 자바를 공부하면서 작성한 글입니다. 현업에서 GC를 경험해보지 않았기 때문에, 설명이 부족할 수 있습니다.
궁금한 점/헷갈리는 파트는 댓글로 피드백 주시면 보완하겠습니다 :)
'Tech > 배워서 남주기' 카테고리의 다른 글
Redis로 다중 서버 환경에서 로그인 정보 불일치 문제 해결하기 (0) | 2022.10.08 |
---|---|
[객체 지향적 설계] 디자인 패턴과 레이어드 아키텍처 적용하기 (0) | 2022.09.29 |
해시 암호화가 충분하지 않을 때 - BCrypt (솔트) 적용 (0) | 2022.09.09 |
인터셉터 / 커스텀 애노테이션 활용하여 로그인 강제 (0) | 2022.09.09 |
[인증] JWT 와 세션 방식 비교 (0) | 2022.07.16 |