2. garbage collection 과정
1) mark, sweep
garbage collection 과정(알고리즘)은 mark, sweep, compact 작업으로 구성된다.
- mark
더 이상 변수에 의해 참조되지 않은 객체가 garbage 이다.
garbage를 찾는 작업이 mark 이다.
mark 작업은, 모든 변수를 뒤져서, 그 변수가 참조하는 객체에 표시(mark)를 한다.
- sweep
mark 표시가 없는 객체는, 변수에 의해 참조되지 않는 garbage 이다.
garbage 객체를 삭제하는 작업이 sweep 이다.
참조 되지 않는 객체 (mark 표시가 없는 객체)를 삭제하면, 빈 공간이 흩어져 있게 된다.
새 객체를 생성할 때, 적당한 빈 공간을 찾아야 하는 부담이 있다.
객체를 생성하기에는 너무 작은 빈 공간들이, 객체들 사이에 존재하게 되어, 메모리가 낭비된다.
- compact
mark, sweep은 필수 작업이지만, compact는 필수 작업이 아니다.
sweep 작업 결과 삭제되지 않고 살아 남은 객체들은, 메모리에 듬성듬성 위치하게 된다.
이 객체들을 한쪽으로 몰아서, 객체들이 차지하는 영역과, 비어있는 영역을 구분하여,
메모리에 빈 영역을 확보하는 작업이 compact 이다.
새 객체를 생성할 때, 빈공간의 시작 부분에 생성하면 되므로 빠르다.
compact 작업에 시간이 걸리지만,
compact 작업 후에는, 객체 생성이 빠르고, 메모리 낭비가 없다.
2) young generation / old generation
예를 들어서, 생성된 java 객체가 시간이 지나면 쓰레기(garbage)가 되어 청소(garbage collection) 대상이 된다고 상상해 보자.
생성된 객체의 대부분은 짧은 시간 안에 쓰레기가 된다. -> 이런 특징을 또 이용해서 영역을 나눈다.
효율적인 쓰레기 청소를 위해서,
메모리 영역을 young generation 영역과 old generation 영역으로 나눈다.
객체를 처음 생성할 때 young generation 영역에 생성한다.
생성된 대부분의 객체는 금방 쓰레기가 되기 때문에, young generation 영역은 자주 청소(garbage collection) 해야 한다.
young generation 영역에서 정해진 시간 이상 제거되지 않고 오래 살아남은 객체는,
old generation 영역으로 옮겨 놓는다.
old generation 영역으로 옮겨진 객체들은, 비교적 오래 생존할 확률이 높다.
따라서 old generation 영역은 자주 청소할 필요가 없고, 가끔 청소하면 된다.
3) minor garbage collection / major garbage collection
young generation 영역은 자주 청소해야 한다. 이것을 minor garbage collection 이라고 부른다.
아주 가끔 old generation 영역과 young generation 영역을 전부 대청소 해주어야 한다.
이것을 major garbage collection 혹은 full garbage collection 이라고 부른다.
4) card table
old ganeration 영역의 객체의 멤버 변수가, young generation 영역의 객체를 참조하는 경우는 드물다.
(오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재하기 때문)
old ganeration 영역의 객체의 멤버 변수에 의해서 참조되는 객체는, garbage가 아니다.
따라서 young generation 영역을 청소할 때,
old generation generation 영역의 객체의 멤버 변수들도 다 뒤져서 mark 해야 하는데, 이 작업에 시간이 많이 걸린다.
young generation 영역은 자주 garbage collection 해야 하는데,
그때마다 old generation 영역의 멤버 변수들을 전부 뒤지는 것은 부담이다.
그래서 다음과 같은 방법을 사용한다.
old generation 영역의 멤버 변수가 young generation 영역의 객체를 참조하는 경우에,
이 정보를 card table에 기록한다.
이 card table 기록 방법의 장단점은 다음과 같다.
-
단점
old generation 영역의 멤버 변수에 young generation 영역의 객체를 대입할 때마다
card table에 그 정보를 기록해야 한다. -
장점
young generation 영역을 청소하기 위해서, mark 할 때, old generation 영역의 멤버 변수를 전부 뒤질 필요 없고, card table 기록만 보면 된다.
단점의 손해 보다, 장점의 이익이 훨씬 크기 때문에, card table 기록을 사용하여 garbage collection 한다.
5) Heap 영역 구조
-
Young Generation, Old Generation
Heap 영역의 일부이다.
여기에는 new 연산자로 생성된 객체들과 배열들이 들어있다. -
Permanent Generation (Metaspace)
Permanent Generation에는, 클래스와 메소드에 대한 메타 정보가 저장된다.- 클래스 구조에 대한 정보
- 메소드들의 bytecode
- static 멤버 변수
Java8 이후부터는 Permanent Generation 영역의 이름이 Metaspace로 바뀌었고,
이 공간의 메모리 관리 기능도 개선되었다.
Java8 부터는 Metaspace를 Heap 영역의 일부로 보지 않고, 독립된 영역으로 본다.
3. young generation 영역의 garbage collection 과정
1) eden 영역, survivor 영역
young generation 영역은 한 개의 eden 영역과 두 개의 survivor 영역으로 나뉜다.
두 survivor 영역을 각각 survivor0, survivor1 라고 하자.
처음 실행할 때, eden 영역과 두 survivor 영역이 전부 빈 상태이다.
생성되는 객체는 처음에 eden영역에 위치한다.
- before garbage collection
- garbage collection #1
eden 영역이 꽉 차면, young generation 영역 전체를 garbage collection 한다. (mark, sweep)
(young generation 영역 전체 = eden 영역 + 두 survivor 영역)
young generation 영역을 garbage collection 하는 것은 minor garbage collection 이라고 부른다.
garbage collection 하고 난 후,
eden 영역에서 살아남은 객체들을 전부, survivor0 영역으로 차곡 차곡 옮긴다. (compact)
survivor0 영역으로 이동된 객체의 살아남은 횟수를 1로 기록한다.
garbage collection 결과, eden 영역과 survivor1 영역은 빈 공간이 된다.
- garbage collection #2
객체들이 생성되어 eden 영역이 또 꽉 차면, young generation 영역 전체를 garbage collection 한다.
eden 영역에서 살아남은 객체들을 전부, 비어있던 survivor1 영역으로 옮긴다.
이 객체들의 살아남은 횟수를 1로 기록한다.
그리고 survivor0 영역에서 살아남은 객체들도 survivor1 영역으로 옮긴다.
이 객체들의 살아남은 횟수를 2로 기록한다.
garbage collection 결과, eden 영역과 survivor0 영역은 빈 공간이 된다.
- garbage collection #3
객체들이 생성되어 eden 영역이 또 꽉 차면, young generation 영역 전체를 garbage collection 한다.
eden 영역에서 살아남은 객체들을 전부, 비어있던 survivor0 영역으로 옮긴다.
이 객체들의 살아남은 횟수를 1로 기록한다.
그리고 survivor1 영역에서 살아남은 객체들도 survivor0 영역으로 옮긴다.
이 객체들의 살아남은 횟수에 1을 더해서 기록한다.
2) old generation 영역으로 승진
- garbage collection #9
9번째 garbage collection을 수행하면, 살아남은 횟수가 9인 객체가 존재할 수 있다.
이 객체들은 old generation 영역으로 이동한다.
- old generation 영역의 garbage collection
old generation 영역을 차지하는 객체의 양이 디폴트 기준을 넘으면,
old generation 영역과 young generation 영역 전체에서 garbage collection이 진행된다.
full GC, major GC
3) copying collector
young generation 영역의 garbage collection 작업을 담당하는 엔진을, copying collector 라고 부른다.
young generation 영역의 GC는 mark 작업과 copy 작업으로 구성된다.
-
mark 작업
참조되는 객체과, 참조되지 않는 객체를 식별하게 된다.
참조되지 않는 객체가 garbage 이다.
-
copy 작업
두 survivor 영역 중 한 곳은 언제나 빈 공간이다.
mark 작업에서 식별된 참조되는 객체들을, 이 빈 공간에 차곡 차곡 복사한다.
4. Java Garbage Collector 종류
Java VM(Virtual Machine) 내부에서 garbage collection 작업을 수행하는 엔진을 garbage collector라고 부른다.
Java VM 내부에 garbage collector가 여러 개 구현되어 있고,
Java VM을 실행할 때 command line parameter로 garbage collector를 선택할 수 있다.
1) Serial Garbage Collector
CPU 코어 수가 1개일 때, serial GC가 사용된다.
minor GC, magor GC 둘 다 싱글 스레드로 실행된다.
compact 작업까지 수행한다.
CPU가 많은 서버에서도 serial GC를 사용하기도 하는데, 서버 한 대에 JVM 여러 개를 동시에 실행하는 경우다.
서버 운영체제에서 JVM 한 개는, 하나의 운영체제 프로세스(process)로 실행된다.
하나의 운영체제 프로세스 내부에 스레드가 여러 개 생성될 수 있다.
즉 서버 한 대에 여러 개의 JVM 프로세스가 실행되는 경우에, 각 JVM 내부에서는 serial GC를 사용하기도 한다.
JVM 프로세스 뿐만 아니라, 다른 프로세스들도 같이 실행되는 서버에서,
JVM 프로세스가 CPU 코어를 독점하는 것을 막기 위해, serial GC를 선택할 수 있다.
- Serial GC의 장점
Serial GC 작업이 진행되는 동안, 다른 작업들이 멈춰야 하는 대신, GC 작업이 효율적으로 진행된다.
비유를 하자면, 대청소를 하는 동안, 모든 작업을 중단하고 오로지 청소만 한다면,
효율적인 청소를 할 수가 있다.
즉 다른 GC 작업에 비해서, Serial GC 작업에 투입되어야 하는 CPU의 작업 총량이 적다.
- Serial GC를 선택하는 경우 요약
- CPU 코어가 한 개 뿐이다.
- CPU 코어가 여러 개이지만, JVM 프로세스 혼자 CPU 코어를 독점하면 안된다.
- Serial GC 작업 동안의 멈춤(stop-the-word) 현상을 허용할 수 있다. (길면 1~2초 정도가 될 수 있다고 함)
- heap의 크기가 100mega 이하 정도로 작다.
- command line option
-XX:+UseSerialGC
명령의 예:
java -XX:+UseSerialGC -jar demo.jar
2) Parallel Garbage Collector
young generation영역의 garbage collection을 멀티 스레드로 실행한다.
CPU 코어가 여러 개인 경우에, parallel GC가 디폴트로 선택되고, 코어 수 만큼의 스레드로 GC를 수행한다.
parallel GC 는 parallel GC 와 parallel Old GC 로 나뉜다.
young generation 영역의 GC를 멀티 스레드로 실행하는 것은 parallelGC 와 parallelOldGC 에서 공통이다.
young generation 영역의 GC = mark + copy
mark + copy 작업은 멀티 스레드로 실행될 수 있다.
- Parallel GC
old generation 영역의 GC = 싱글 스레드
old generation 영역의 GC = mark + sweep + compact
sweep + compact 작업은 멀티 스레드로 실행될 수 없고 싱글 스레드로 수행되어야 한다.
- Parallel Old GC
old generation 영역의 GC = 멀티 스레드
old generation 영역의 GC = mark + summary + compact
summary + compact 작업은 멀티 스레드로 실행될 수 있다.
Parallel Old GC를 Parallel Compating GC라고 부르기도 한다.
- Parallel GC를 선택하는 경우 요약
- CPU 코어들을 전부 활용하여 JVM 프로세스의 성능을 최대로 높이자
- JVM 프로세스가 CPU 코어들을 전부 독점해도 된다.
- Parallel GC 동안의 멈춤(stop-the-world) 현상을 허용할 수 있다. (Serial GC 경우보다는 짧다)
- CPU 코어 수가 많고, 메모리 용량도 큰 경우에, parallel GC가 디폴트로 선택된다.
- command line option
-XX:+UseParallelGC
<- Parallel GC 선택
-XX:+UseParallelOldGC
<- Parallel Old GC 선택
-XX:ParallelGCThreads=스레드수
<- Parallel GC가 사용할 스레드 수를 제한하기 위한 선택 옵션
이 옵션을 지정하지 않으면 CPU 코어 수 만큼의 스레드를 사용
3) Concurrent Mark Sweep Collector
Concurrent Mark Sweep Collector에서 앞글자만 따서 CMS collector라고 부른다.
concurrent low pause collector 라고 부르기도 한다.
GC 작업 동안의 정지(stop-the-world) 기간을 최대로 줄이기 위해 선택한다.
GC 작업 동안 애플리케이션 스레드도 같이 실행될 수 있도록 고안된 GC 이기 때문에, 정지 기간이 매우 짧다.
CMS GC는 총 6단계의 작업으로 구성되는데, 이 중에서 2 단계만 애플리케이션이 정지되고,
4 단계에서는 애플리케이션 스레드와 GC 스레드가 동시에 실행된다.
GC 작업이 애플리케이션 스레드와 동시에 진행될 수 있어야 하기 때문에,
GC 작업이 약간 비효율적으로 진행된다.
이 비효율 때문에, 정해진 시간 동안 처리한 작업 양을 비교하면, CMS GC가 parallel GC 보다 뒤쳐진다.
그리고 comat 작업을 포함하지 않아서, 메모리도 낭비된다.
정해진 시간 동안 처리한 작업 양 = throughput
- full stop-the-world collection
old generation 영역이 가득 찬 경우에는, 애플리케이션 스레드들이 모두 멈춘 상태에서(stop-the-world),
전체 메모리 영역에 대한 garbage collection이 진행된다. 이 작업의 정지 기간이 꽤 길어진다.
이때에는 compact 작업도 포함된다.
- 장점
정지(stop-the-world) 기간이 매우 짧다.
- 단점
- compat 작업을 하지 않기 때문에, 메모리가 낭비된다.
- 정해진 시간 동안 처리한 작업 양(throughput)이 parallel GC 보다 못하다.
- 가끔 full stop-the-world collection 작업이 필요해 질 수 있고, 이때는 정지 기간이 길다.
- CMS GC를 선택하는 경우 요약
- GC 동안의 멈춤(stop-the-world) 현상을 허용할 수 없고, 애플리케이션이 언제나 즉시 반응해야 한다.
- JVM 프로세스가 CPU 코어들을 전부 독점해도 된다.
- heap의 크기가 4GB 이하이다. (heap의 크기가 4GB 이상이면, G1 GC를 사용해야 한다)
- command line option
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads=스레드 수
4) G1 Garbage Collector
G1 garbage collector는 Java7 부터 제공된다.
장기적으로 CMS collection를 대체하려고 개발된 GC이다.
4GB 이상 크기의 heap에 대한 효율적인 GC를 위해서 개발되었다.
full stop-the-world collection 작업 필요한 상황의 발생 확률이 CMS GC 보다 낮다.
CMS GC와는 달리 compat 작업을 포함한다.
- command line opotion
-XX:+UseG1GC
5) JVM 프로세스 수
- 전략#1: JVM 프로세스 한 개
서버 한 대에 JVM 프로세스 한 개만 실행.
Java로 구현된 서비스들을 모두 이 프로세스에서 실행.
서비스를 동시에 여러 개 실행하려면, 많은 메모리가 필요할 테니, JVM의 heap 크기를 4GB 이상으로 설정.- 장점
- 서비스들 사이에 직접 메소드 호출할 수 있고, 파라미터나 리턴 값으로 데이터를 전달할 수 있다.
- 단점
- 4GB 보다 큰 heap을 GC 할 때, stop-the-world 시간이 10초 정도로 길어질 수 있다.
이 단점은 G1 GC를 채택하여 해결할 수 있다. - 어느 한 서비스에 버그가 있어서 에러가 발생하면, 같은 JVM 에서 실행되는 다른 서비스들에게
영향을 줄 수 있다.
- 4GB 보다 큰 heap을 GC 할 때, stop-the-world 시간이 10초 정도로 길어질 수 있다.
- 장점
- 전략#2: JVM 프로세스 여러 개
서버 한대에 JVM 프로세스 여러 개를 실행.
Java로 구현된 서비스들 각각을 별개의 JVM 프로세스에서 실행.
각각의 JVM 프로세스는 서비스를 하나만 실행할 테니, JVM의 heap 크기를 적당한 정도로 제한.- 장점
- 각각의 JVM은 상대적으로 작은 크기의 heap을 GC 하기 때문에, stop-the-wolrd 시간이 짧다.
- 어느 한 JVM 프로세스에서 에러가 발생해도, 다른 JVM 프로세스에 영향을 줄 수 없다.
- 서비스 단위로 배포하고 관리하기 편하다. Docker를 이용하면, 더욱 편하다.
- 단점
- 서비스들 사이에 직접 메소드 호출은 불가능하고, 명령이나 데이터를 주고 받기 위해 네트웍 통신이 필요하다.
- 장점
6) Java VM command line paramter
Java VM(Virtual Machine)을 실행하기 위한 java.exe 명령의 command line parameter 중에서
메모리 설정과 관련된 것들은 다음과 같다.
-
-Xms숫자
heap 영역의 초기 크기를 설정한다.
예:-Xms6m
= 6mega로 설정
-
-Xmx숫자
heap 영역의 최대 크기를 설정한다.
예:-Xmx80m
= 80mega로 설정
-
-Xmn숫자
young generation 영역의 크기를 설정한다.
-
-XX:+UseStringDeduplicationJVM
Java8 update20 JVM의 G1 Collector에는 String deduplication 기능이 추가되었다.
GC 과정에서, 내용이 동일한 String 객체들을 찾아서, 중복된 부분을 제거해 주는 기능이다.