1. GC에서 사용하는 알고리즘은 무엇이 있고, Java는 어떤 알고리즘을 사용하나요?
GC(Garbage Collection)는 Mark-and-Sweep, Stop-the-World, Copying, Generational, Parallel, Concurrent 등 다양한 알고리즘을 사용하며, Java는 특정 GC 알고리즘(Serial, Parallel, CMS, G1, ZGC 등)을 조합하여 메모리를 관리합니다.
GC 알고리즘은 객체의 생명 주기와 메모리 할당 패턴에 따라 다르게 동작합니다:
- Mark-and-Sweep: 살아있는 객체를 식별(Mark)하고, 쓰이지 않는 객체를 제거(Sweep).
- Copying: 살아있는 객체만 새로운 공간으로 복사하여 메모리 단편화를 줄임.
- Generational: Young, Old Generation으로 나누어, Young Generation에서 주로 GC를 실행.
- Parallel: 여러 스레드가 동시에 GC 작업을 수행.
- Concurrent: 어플리케이션 실행 중에도 일부 GC 작업 수행.
Java는 버전과 설정에 따라 Serial GC, Parallel GC, CMS, G1 GC, ZGC, Shenandoah GC 등을 사용합니다.
Java 8
- 기본 GC:
- Parallel GC (Throughput Collector): 기본 GC로 설정되어 있으며, 다수의 CPU 코어를 사용하여 GC 작업을 병렬로 수행. Throughput(처리량)을 중시하여 GC의 일시 중단 시간을 줄이는 데 초점.
Java 9
- 주요 변경 사항:
- G1 GC 기본값 채택: 기존의 Parallel GC 대신 G1 GC가 기본값으로 설정.
G1 GC는 메모리를 Region으로 나누고, GC 작업을 병렬로 수행하며, 긴 Stop-the-World 시간을 줄이는 데 적합.
- G1 GC를 기본값으로 설정한 이유는 CMS보다 효율적인 메모리 관리와 안정성 제공.
Java 21 (최신 LTS)
- ZGC 개선: 최대 힙 크기 지원이 64TB까지 증가. 대기 시간이 더 짧아지고 안정성 강화.
- Parallel GC와 G1 GC의 성능 향상:
- Parallel GC는 Throughput에 최적화.
- G1 GC는 대기 시간과 처리량의 균형을 더 효과적으로 맞춤.
2. Java 8 기준으로, GC는 어떤 방식으로 수행되나요?
Java 8에서 GC는 기본적으로 Parallel GC를 사용하며, Young Generation과 Old Generation을 나누는 Generational GC 구조를 따릅니다.
Java 8의 GC 수행 방식은 다음과 같은 특징을 가집니다:
메모리 단편화란?
- GC가 Sweep 단계에서 참조되지 않는 객체를 제거하고 나면, 메모리에는 비어 있는 공간(free space)과 사용 중인 공간(occupied space)이 섞여 있게 됩니다.
- 이로 인해 빈 공간이 조각(fragment)처럼 여기저기 흩어져 있습니다.
- 만약 새로운 큰 객체를 할당해야 할 경우, 빈 공간의 크기가 충분하지 않으면 메모리를 활용하지 못하는 문제가 발생할 수 있습니다.
- Parallel GC (기본값):
- 여러 스레드가 동시에 GC 작업을 수행하여 Throughput(처리량)을 극대화.
- 애플리케이션의 중단 시간(Pause Time)은 상대적으로 길지만, 전체적인 처리 속도는 높습니다.
Java 8에서는 GC가 Generational 구조(Young과 Old Generation)를 기반으로 하여 동작하며, 기본값으로 Parallel GC를 사용해 멀티스레드를 활용하여 높은 처리량을 제공하는 방식으로 수행됩니다.
3. 왜 Heap 영역은 Young Generation과 Old Generation으로 나뉘나요?
객체의 생명 주기가 다르기 때문에, Young과 Old Generation으로 나눠 효율적인 메모리 관리와 GC 비용 절감을 가능하게 합니다.
- 대부분의 객체는 단명 객체로, 빠르게 할당 후 해제됩니다.
- Young Generation: 짧은 생명 주기를 가진 객체 관리. Minor GC가 자주 발생.
- Old Generation: 장수 객체 관리. Major GC가 드물게 발생하나 시간이 오래 걸림.
- 이런 구조로 인해 GC 빈도와 비용을 최적화할 수 있습니다.
java -Xms512m -Xmx1024m -XX:NewRatio=2 MyApp
(위 예시에서 Young:Old = 1:2로 설정)
Young과 Old Generation의 분리는 객체의 생명 주기에 따른 효율적인 GC 실행을 위해 설계된 구조입니다.
4. GC의 실행 방식을 아는 만큼 설명해 주세요.
GC는 객체 생존 여부를 확인(Mark)하고, 필요시 불필요한 객체를 제거(Sweep)하며, 메모리 단편화를 방지하기 위해 객체를 이동(Compaction)하는 방식으로 실행됩니다.
- Mark Phase: GC Root에서 시작하여 Heap의 모든 객체를 스캔해 참조 중인 객체를 식별.
- Sweep Phase: 참조되지 않는 객체를 메모리에서 제거.
- Compaction Phase: 메모리에 남아 있는 살아 있는 객체를 한쪽으로 정리(재배치)하여 단편화 방지.
- Stop-the-World: GC 실행 중 JVM은 애플리케이션을 일시 중단. ( 메모리 관리와 안정적인 GC 수행을 위해 발생. )
GC는 Mark-Sweep-Compact 단계를 통해 메모리를 관리하며, 애플리케이션 성능에 영향을 최소화하기 위해 최적화된 알고리즘을 사용합니다.
5. Java 8과 Java 11의 디폴트 GC 실행 방식은 어떤 것인가요?
- Java 8: 기본적으로 Parallel GC 사용.
- Java 11: 기본적으로 G1 GC 사용.
- Java 8 (Parallel GC): GC 작업을 병렬로 처리하여 Throughput(처리량)을 극대화.
- Java 11 (G1 GC): Pause 시간을 줄이고 예측 가능한 성능 제공.
Java 8은 고성능을 위해 Parallel GC를 사용하며, Java 11은 낮은 지연시간을 제공하기 위해 G1 GC를 기본값으로 사용합니다.
6. G1 GC에 대해 설명해 주세요.
G1 GC(Garbage-First Garbage Collector)는 Heap 메모리를 Region 단위로 관리하며, Garbage가 많은 Region을 우선적으로 정리해 Full GC를 최소화합니다.
1. Region 기반 메모리 관리
- Heap 메모리를 고정 크기의 Region으로 나누어 관리합니다.
- Region은 Young, Old, Humongous 등 다양한 역할을 수행하며, 필요에 따라 동적으로 크기를 조정할 수 있습니다.
2. Garbage-First(G1)
- 이름처럼, Garbage가 가장 많은 Region을 우선적으로 정리하여 GC 효율을 높입니다.
- 이를 통해 Full GC를 지연시키거나 최소화합니다.
3. Concurrent GC 작업
- G1 GC는 Concurrent 방식으로 동작하여, 애플리케이션이 실행 중인 동안에도 일부 GC 작업을 병렬적으로 수행합니다.
- 이는 긴 Stop-the-World(중단 시간)을 줄이는 데 도움을 줍니다.
4. Pause Time Goal (목표 중단 시간)
- G1 GC는 사용자가 설정한 목표 중단 시간 (Pause Time Goal)을 기반으로 작업을 최적화합니다.
- GC 주기와 Region 정리 작업은 이 목표를 초과하지 않도록 설계됩니다.
5. Mixed GC
- Young Region과 Old Region을 동시에 정리(Mixed GC)하는 방식으로 전체 메모리를 관리합니다.
- Young GC가 반복적으로 발생한 후, 필요에 따라 Old Region을 추가로 정리합니다.
7. G1 GC의 Heap 구조를 설명해 주세요.
G1 GC는 Heap을 고정 크기의 Region으로 나누어 관리하며, Young과 Old Generation이 여러 Region에 분산됩니다.
- Region: Heap을 동일한 크기의 블록으로 나눔.
- Young, Old, Humongous Region으로 구분.
- Region 단위로 GC를 수행하여 메모리 단편화 방지.
G1 GC의 Region 구조는 메모리 관리 효율을 극대화합니다.
8. 왜 Java 11은 디폴트 GC를 G1 GC로 변경하였을까요?
G1 GC는 낮은 지연시간과 예측 가능한 성능을 제공하며, 대규모 애플리케이션에 적합하기 때문에 기본값으로 채택되었습니다.
- 낮은 지연시간: Stop-the-World 시간을 최소화.
- 예측 가능성: GC 지연시간을 설정 가능.
- 대규모 시스템 적합: 대규모 Heap에서도 효율적으로 작동.
Java 11은 G1 GC를 디폴트로 채택하여 현대 애플리케이션의 성능 요구를 충족시켰습니다.
GC...GD의 형...농담이고, GC Monitoring과 메모리 누수에 대한 내용도 있으면 좋겠네요
수고하셨어요!