자바의 Runtime data area
- PC 레지스터
- JVM 스택
- 힙(Heap) => GC 발생
- 메서드 영역
- 런타임 상수(constant) 풀
- 네이티브 메서드 스택
- Class Loader Subsystem
- 클래스나 인터페이스르 JVM으로 로딩하는 기능을 수행
- Execution Engine
- 로딩된 크래스의 메서드들에 포함되어 있는 모든 인스트럭션 정보를 실행
Heap 메모리
- 클래스 인스턴스, 배열
- 공유(shared) 메모리
- 여러 스레드에서 공유하는 데이터들이 저장
Non-heap 메모리
- Method Area
- 메서드 영역은 모든 JVM 스레드에서 공유한다.
- Java Stacks
- 스레드가 시작할 때 JVM 스택이 생성된다.
- 메서드가 호출되는 정보인 프레임(frame)이 저장된다.
- 지역 변수와 임시 결과, 메서드 수행과 리턴에 관련된 정보들도 포함된다.
- 스레드가 시작할 때 JVM 스택이 생성된다.
- PC Registers
- 자바의 스레드들은 각자의 PC(Program Counter) 레지스터를 갖는다.
- 네이티브한 코드를 제외한 모든 자바 코드들이 수행될 때 JVM의 인스트럭션 주소를 PC 레지스터에 보관한다.
- Native Method Stacks
- 자바 코드가 아닌 다른 언어로 된 코드들이 실행하게 될 때의 스택 정보를 관리한다.
GC의 원리
- 메모리 할당
- 사용 중인 메모리 인식
- 사용하지 않는 메모리 인식
- [1단계]
- 메모리에 객체가 생성되면, 가장 왼쪽인 Eden 영역에 객체가 지정된다.
- [2단계]
- Eden 영역에 데이터가 꽉 차면, 이 영역에 있던 객체는 Survivor 영역으로 옮겨지거나 삭제된다.
- 두 개의 Survivor 영역 사이에 우선 순위가 있는 것은 아니다.
- 이 두 개의 영역 중 한 영역은 반드시 비어 있어야 한다.
- 그 비어 있는 영역에 Eden 영역에 있던 객체 중 GC 후에 살아 남은 객체들이 이동한다.
- [3단계]
- Eden 영역에 있던 객체는 Survivor 영역의 둘 중 하나에 할당된다.
- 할당된 Survivor 영역이 차면, GC가 되면서 Eden 영역에 있는 객체와 꽉 찬 Survivor 영역에 있는 객체가 비어 있는 Survivor 영역으로 이동한다.
- 이러한 작업을 반복하면서 Survivor 1과 2를 왔다갔다 하던 객체들은 Old 영역으로 이동한다.
- [4단계]
- 객체의 크기가 아주 큰 경우 바로 Old 영역으로 이동한다
- 예를 들어, Survivor 영역의 크기가 16MB인데 20MB를 점유하는 객체가 Eden 영역에서 생성되면 Survivor 영역으로 옮겨 갈 수 없고 바로 Old 영역으로 이동하게 된다.
GC의 종류
- Minor GC: Young 영역에서 발생하는 GC
- Major GC: Old 영역이나 Perm 영역에서 발생하는 GC
5가지 GC 방식
Serial Collector
- Young 영역과 Old 영역이 연속적으로 처리되며 하나의 CPU를 사용
- Sun에서는 이 처리를 수행할 때를 Stop-the-world라고 표현한다.
- [1단계]
- 살아 있는 객체들은 Eden 영역에 있다
- [2단계]
- Eden 영역이 꽉차게 되면 To Survivor 영역(비어 있는 영역)으로 살아 있는 객체가 이동한다.
- 이때 Survivor 영역에 들어가기에 너무 큰 객체는 바로 Old 영역으로 이동한다.
- 그리고 From Survivor 영역의 살아 있는 객체는 To Survivor 영역으로 이동한다.
- [3단계]
- To Survivor 영역이 꽉 찼을 경우,
- Eden 영역이나 From Survivor 영역에 남아 있는 객체들은 Old 영역으로 이동한다.
- Old 영역이나 Perm 영역에 있는 객체들은 Mark-sweep-compact 콜렉션 알고리즘을 따른다.
- 쓰이지 않는 객체를 표시해서 삭제하고 한 곳으로 모으는 알고리즘
- Old 영역으로 이동된 객체들 중 살아 있는 객체를 식별(mark).
- Old 영역의 객체들을 훑는 작업을 수행하여 쓰레기 객체를 식별(sweep).
- 필요 없는 객체들을 지우고 살아 있는 객체들을 한 곳으로 모은다(compaction).
Parallel Collector
- 다른 CPU가 대기 상태로 남아 있는 것을 최소화하는 것을 목표로 한다.
- Serial Collector와 달리 Young 영역에서의 콜렉션을 병렬(Parallel)로 처리한다.
- 많은 CPU를 사용하기 때문에 GC의 부하를 줄이고 애플리케이션의 처리량을 증가시킬 수 있다.
- Old 영역의 GC는 Serial Collector와 마찬가지로 Mark-sweep-compact 콜렉션 알고리즘을 사용한다.
- 이 방법으로 GC를 지정하려면 -XX:+UseParallelGC 옵션을 추가하면 된다.
Parallel Compacting Collector
- Parallel Collector와 다르게 Old 영역 GC에서 새로운 알고리즘을 사용
- Marking: 살아 있는 객체를 식별하여 표시
- Summary: 이전에 GC를 수행하여 컴팩션된 영역에 살아 있는 객체의 위치를 조사하는 단계
- Compaction: 컴팩션을 수행하는 단계. 수행 이후에는 컴팩션된 영역과 비어 있는 영역으로 나뉜다.
- 병렬 콜렉터와 동일하게 이 방식도 여러 CPU를 사용하는 서버에 적합하다.
- GC를 사용하는 스레드 개수는 -XX:ParallelGCThreads=n 옵션으로 조정할 수 있다.
- 이 방식을 사용하려면 -XX:UseParallelOldGC 옵션을 추가하면 된다.
Concurrent Mark-Sweep(CMS) Collector
- 힙 메모리 영역의 크기가 클 때 적합하다.
- Young 영역에 대한 GC는 Parallel Collector와 동일하고, Old 영역은 다음 단계를 거친다.
- Initial mark: 매우 짧은 대기 시간으로 살아 있는 객체를 찾는 단계
- Concurrent marking: 서버 수행과 동시에 살아 있는 객체에 표시를 해놓는 단계
- Remark: Concurrent marking 단계에서 표시하는 동안 변경된 객체에 대해서 다시 표시하는 단계
- Concurrent sweep: 표시되어 있는 쓰레기를 정리하는 단계
- CMS 콜렉터 방식은 2개 이상의 프로세서를 사용하는 서버에 적당하다(웹서버).
- 이 방식을 사용하려면 -XX:UseConcMarkSweepGC 옵션을 추가하면 된다.
G1 Collector
- 각 바둑의 사각형을 region이라고 하는데,
- Young 영역과 Old 영역이 물리적으로 나뉘어 있지 않고 각 구역의 크기는 모두 동일하다.
- 이 바둑판 모양의 구역이 각각 Eden, Survivor, Old 영역의 역할을 변경해 가면서 하고,
- Humongous라는 영역도 포함된다.
- 몇 개의 구역을 선정하여 Young 영역으로 지정한다.
- 이 Linear 하지 않은 구역에 객체가 생성되면서 데이터가 쌓인다.
- Young 영역으로 할당된 구역에 데이터가 꽉 차면 GC를 수행한다.
- GC를 수행하면서 살아있는 객체들만 Survivor 구역으로 이동시킨다.
- 이렇게 살아 남은 객체들이 이동된 구역은 새로운 Survivor 영역이 된다.
- 그 다음에 Young GC가 발생하면 Survivor 영역에 계속 쌓는다.
- 그러면서 몇 번의 aging 작업을 통해서 Old 영역으로 승격된다.
G1의 Old 영역 GC는 CMS GC의 방식과 비슷하며 아래 여섯 단계로 나뉜다.
- [1단계] Initial mark
- Old 영역에 있는 객체에서 Survivor 영역의 객체를 참조하고 있는 객체들을 표시한다.
- [2단계] Root region scanning
- Old 영역 참조를 위해서 Survivor 영역을 훑는다. 이 작업은 Young GC가 발생하기 전에 수행된다.
- [3단계] Concurrent mark
- 전체 힙 영역에 살아있는 객체를 찾는다. 만약 이때 Young GC가 발생하면 잠시 멈춘다.
- [4단계] Remark
- 힙에 살아있는 객체들의 표시 작업을 완료한다.
- 이때 Snapshot-At-The-Beginning(SATB) 알고리즘을 사용하며 이는 CMS GC에서 사용하는 방식보다 빠르다.
- [5단계] Cleaning
- 살아있는 객체와 비어 있는 구역을 식별하고, 필요없는 객체들을 지운다.
- 그리고 나서 비어있는 구역을 초기화한다.
- [6단계] Copy
- 살아있는 객체들을 비어있는 구역으로 모은다.
'개발서적 > 자바 성능 튜닝 이야기' 카테고리의 다른 글
[자성튜이] 성능 튜닝을 위한 기초 법칙 (0) | 2024.09.16 |
---|---|
[자성튜이] 반드시 튜닝해야 하는 대상 (0) | 2024.09.16 |
[자성튜이] JVM은 도대체 어떻게 구동될까 (0) | 2024.09.16 |
[자성튜이] 서버를 어떻게 세팅해야 할까? (1) | 2024.09.16 |
[자성튜이] JSP와 서블릿, Spring (0) | 2024.09.16 |