Garbage Collector 의 성능은 처리량(Throughput), 지연 시간(Latency), 메모리 사용량(footprint) 세가지 요소로 측정된다. 이 세가지는 모두 만족시키기 어렵다.
Garbage Collector 를 알아볼때에는 각 컬렉터들이 어떤 성능을 중요시하는지 알고 보는게 좋다.
지연 시간은 여러 요소에 의해 바뀌겠지만, Garbage Collector 관점에서는 일시 정지 시간과 관련이 많다. Stop-The-World 라고 하는 일시 정지 시간은 죽은 객체를 판별(mark)하거나, 살아남은 객체를 모으는(compact) 과정에서 필요하다.
이 STW 는 애플리케이션 전체를 멈추게 하기 때문에 P99, P999 같이 튀는 latency 를 유발할 수 있다. 멈춰있는 시간이 길수록, 그 사이에 해야 할 일이 많이 쌓일수록 요청중 튀는 latency 가 발생할 확률이 높다.
따라서 CMS, 셰넌도어, ZGC 같은 경우는 STW 를 최소한으로 줄이기 위한 방법들로 발전해 왔다. 큰 틀에서는 mark, compact 과정을 유저 스레드와 동시에 실행하는 방법을 각 garbage collector 에서 다르게 구현한다.
지연 시간이 짧은 garbage collector 는 유저 대상으로 하는 서버 애플리케이션에서 적절하다. java 언어가 서버 애플리케이션 개발에서 가장 많이 쓰이기 때문에, 최신의 garbage collector 들은 지연 시간을 최소화 하는 방향으로 진화하고 있다.

처리량은 위와 같다. 사용자 코드 실행 시간이 99초, GC 시간이 1초라면 처리량은 99% 이다.
한정된 CPU 자원에서 GC 를 위해 스레드가 사용되는 비율이 얼마나 되는가를 수치화 한 것이다.
즉 짧은 GC 시간에 많은 양의 객체를 정리할 수 있는 garbage collector 가 처리량이 좋다고 할 수 있다.
보통 짧은 지연 시간을 추구하면 처리량은 낮아진다.
저지연 컬렉터인 ZGC, 셰넌도어의 목표는 지연 시간을 최소로 함과 동시에 G1 에 비해 처리량의 감소가 10% 미만으로 되게끔 하는 것이었다.
처리량이 높은 GC 는 분석 애플리케이션 등 유저와 상호작용이 적은 애플리케이션에 적합하다.
세대 구분 이론에 따른 메모리 layout 을 처리하는 Garbage Collector 들은 세대간 참조를 해결하기 위해 카드 테이블을 관리한다.
이 카드 테이블도 Gacbage Collector 마다 재각각이며, 메모리 사용량이 다르다.
또한, 메모리 사용량은 아니지만 Garbage Collector 들은 카드 테이블 관리에 사후 write barrier 를 사용하거나, ZGC 에서 컬러 포인터 구현에 load barrier 를 쓰는 등 여러가지 barrier 를 사용한다. 이는 애플리케이션에 가하는 실행 오버헤드이며 주시해야 하는 footprint 이다.

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
G1 GC 이전의 GC(Serial, Parallel, CMS) 들은 모두 위와 같은 메모리 레이아웃에서 동작했다.
weak generational hypothesis 에 따르면 새로 생성되는 객체중 대다수는 빠르게 죽기 때문에 Young Generation 의 GC 는 메모리 파편화를 방지하며 객체가 적을 때 효율적인 Mark-Copy 알고리즘을 사용한다.
반대로 Old Generation 의 GC 는 큰 영역을 청소하기 때문에 오래걸린다. 최대한 많은 양을 저장하여 GC 횟수를 줄이기 위해 크기의 반만 사용할 수 있는 Mark-Copy 대신 Mark-Sweep 또는 Mark-Compact 를 사용하는게 좋다.
초창기의 JDK 에서는 Garbage Collector 들이 Young/Old Gen 각각용으로 만들어졌고 조합을 하여 사용 가능했다. 시간이 지남에 따라 Garbage Collector 를 Young/Old 각각 설정할 수 있는 것이 아닌 하나만 설정하면 최적의 조합으로 셋팅되는 방식으로 하나로 합쳐졌다.
예를 들어 CMS 는 Old Gen 용 Collector 이다. 하지만 JDK9 부터는 CMS 를 사용하면 Young Gen 용 Collector 로서 Parnew 가 자동으로 선택된다.
이런 역사를 알아놓으면 이해하기 한층 편할 것 같다.
-XX:+UseConcMarkSweepGC 로 cms 를 사용하면 기본적으로 -XX:+UseParNewGC 가 켜진다. -XX:-UseParNewGC 옵션을 주면 Serial Collector(DefNew young collector) 가 쓰인다.-XX:+UseParNewGC 옵션은 사라졌으며, CMS 선택시 파뉴가 Young 영역 컬렉터로 강제된다.-XX:ParallelGCThreads 로 GC 스레드 수 제한 가능. CMS 쓸때 가능한 옵션.-XX:MaxGCPauseMillis : 정지 시간이 이 시간이 넘지 않도록 노력한다. 이 시간이 너무 적으면 Young 영역의 크기가 적게 할당되어 오히려 처리량이 떨어질 수 있다.-XX:GCTimeRatio : GC 시간이 1% 이상이 되지 않도록 보장. 기본값은 99.-XX:+UseAdaptiveSizePolicy : 가상머신이 성능 모니터링 정보를 수집하여 최적의 정지 시간과 처리량을 보장하기 위해 -Xmn, -XX:SurvivorRatio 같은 값들을 자동 조정해준다.-XX:+UseSerialGC 로 Young/Gen 모두 시리얼로 동작할 때 쓰이는 MarkSweepCompact GC(이름임) 가 이것이다.
-XX:+UseParallelGC -XX:-UseParallelOldGC이렇게 옵션을 주면 Old 영역에 PS MarkSweep 가비지 컬렉터가 쓰인다.- cms 의 동시 모드 실패시 백업용 컬렉터로도 Serial Old 가 쓰일 수 있다.
-XX:+UseParallelGC 옵션으로 Young Gen 에는 PS, Old Gen 에는 페러렐 올드를 사용한다.참고
https://openjdk.org/jeps/366
https://www.fasterj.com/articles/oraclecollectors1.shtml
https://stackoverflow.com/questions/16442934/serial-mark-sweep-compact-psoldgen-ps-stands-for?utm_source=chatgpt.com
https://blog.ragozin.info/2011/12/garbage-collection-in-hotspot-jvm.html
https://stackoverflow.com/questions/39929758/ps-marksweep-is-which-garbage-collector