이번 글은 Garbage Collector의 The Parallel Collector에 대해 정리했습니다.
#6. The Parallel Collector
The parallel collector (also referred to here as the throughput collector) is a generational collector similar to the serial collector. The primary difference between the serial and parallel collectors is that the parallel collector has multiple threads that are used to speed up garbage collection.
The parallel collector is enabled with the command-line option -XX:+UseParallelGC. By default, with this option, both minor and major collections are run in parallel to further reduce garbage collection overhead.
병렬 수집기(여기서는 처리량 수집기라고도 함)는 세대별 수집기로, 직렬 수집기와 유사하다. 직렬 수집기와 병렬 수집기 사이의 주요 차이점은 병렬 수집기가 가비지 컬렉션 속도를 높이기 위해 여러 스레드를 사용한다는 점입니다.
병렬 수집기는 명령줄 옵션 -XX:+UseParallelGC로 활성화된다. 기본적으로 이 옵션을 사용하면, 마이너 컬렉션과 메이저 컬렉션 모두 병렬로 실행되어 가비지 컬렉션 오버헤드를 더욱 줄인다.
Number of Parallel Collector Garbage Collector Threads
On a machine with <N> hardware threads where <N> is greater than 8, the parallel collector uses a fixed fraction of <N> as the number of garbage collector threads.
하드웨어 스레드가 <N>개인 머신에서, <N>이 8보다 큰 경우 병렬 수집기는 가비지 수집기 스레드 수로 고정된 <N>의 일부를 사용합니다.
The fraction is approximately 5/8 for large values of <N>. At values of <N> below 8, the number used is <N>. On selected platforms, the fraction drops to 5/16. The specific number of garbage collector threads can be adjusted with a command-line option (which is described later). On a host with one processor, the parallel collector will likely not perform as well as the serial collector because of the overhead required for parallel execution (for example, synchronization). However, when running applications with medium-sized to large-sized heaps, it generally outperforms the serial collector by a modest amount on computers with two processors, and usually performs significantly better than the serial collector when more than two processors are available.
그 비율은 <N>이 큰 값일 때 대략 5/8입니다. <N>이 8보다 작은 경우에는 사용되는 수가 <N>이 됩니다. 일부 플랫폼에서는 이 비율이 5/16으로 떨어집니다. 가비지 수집기 스레드의 구체적인 수는 나중에 설명되는 명령줄 옵션으로 조정할 수 있습니다. 프로세서가 하나인 호스트에서는 병렬 실행(예: 동기화 등)으로 인한 오버헤드 때문에 병렬 수집기가 직렬 수집기만큼 잘 수행되지 않을 가능성이 큽니다. 그러나 중간 크기에서 대형 힙을 사용하는 애플리케이션을 실행할 경우, 두 개의 프로세서를 가진 컴퓨터에서는 직렬 수집기보다 약간 더 나은 성능을 보이며, 보통 두 개 이상의 프로세서가 있는 경우 직렬 수집기보다 훨씬 더 나은 성능을 보입니다.
병렬 수집기는 여러 스레드를 동시에 사용해 가비지 컬렉션 작업을 빠르게 수행합니다. 시스템에 8개 이상의 하드웨어 스레드가 있는 경우, 전체 스레드의 약 5/8(일부 시스템에서는 5/16)을 사용하고, 8개 미만일 경우에는 사용 가능한 모든 스레드를 사용합니다. 또한, 이 스레드 수는 명령줄 옵션을 통해 조정할 수 있습니다. 다만, 프로세서가 하나인 시스템에서는 병렬 실행에 따른 오버헤드 때문에 성능이 떨어질 수 있지만, 두 개 이상의 프로세서나 큰 힙을 사용하는 시스템에서는 병렬 수집기가 훨씬 나은 성능을 보입니다.
스레드를 전부 사용하면 병렬 처리가 더 빠른거 아닌가요? 왜 5/8 비율 혹은 5/16비율로 스레드를 사용할까요?
스레드를 너무 많이 사용하면, 각 스레드 간의 작업 전환(컨텍스트 스위칭) 오버헤드가 커져 CPU가 실제 작업보다 전환 작업에 더 많은 시간을 쓰게 되어 전체 성능이 떨어질 수 있습니다. 또한, 여러 스레드가 동시에 같은 자원에 접근하려고 할 때 자원 경쟁이나 잠금 경합이 발생하여 시스템 효율이 저하될 수 있습니다.
따라서, 이 비율(5/8, 5/16)들은 가비지 컬렉션을 빠르게 수행하면서도 전체 시스템 자원을 너무 많이 점유하지 않도록 하기 위해, 여러 하드웨어와 운영체제 환경에서 실험적으로 결정된 최적의 균형 값입니다.
The number of garbage collector threads can be controlled with the command-line option -XX:ParallelGCThreads=<N>. If you are tuning the heap with command-line options, then the size of the heap needed for good performance with the parallel collector is the same as needed with the serial collector. However, enabling the parallel collector should make the collection pauses shorter. Because multiple garbage collector threads are participating in a minor collection, some fragmentation is possible due to promotions from the young generation to the old generation during the collection. Each garbage collection thread involved in a minor collection reserves a part of the old generation for promotions and the division of the available space into these "promotion buffers" can cause a fragmentation effect. Reducing the number of garbage collector threads and increasing the size of the old generation will reduce this fragmentation effect.
가비지 컬렉터 스레드의 수는 명령줄 옵션 -XX:ParallelGCThreads=<N>으로 제어할 수 있습니다. 만약 명령줄 옵션을 통해 힙을 조정하는 경우, 병렬 수집기를 사용해 좋은 성능을 내기 위해 필요한 힙 크기는 직렬 수집기를 사용할 때 필요한 힙 크기와 동일하다. 그러나 병렬 수집기를 활성화하면 컬렉션 중단 시간이 짧아집니다. 여러 가비지 컬렉터 스레드가 마이너 컬렉션에 참여하기 때문에, 컬렉션 동안 젊은 세대에서 노년 세대로의 승격에 의해 약간의 단편화가 발생할 수 있습니다. 마이너 컬렉션에 참여하는 각 가비지 컬렉션 스레드는 승격을 위해 노년 세대의 일부를 예약하며, 사용 가능한 공간을 이들 "승격 버퍼"로 나누는 것이 단편화 효과를 유발할 수 있다. 가비지 컬렉터 스레드의 수를 줄이고 노년 세대의 크기를 늘리면 이러한 단편화 효과를 줄일 수 있다.
여러 스레드가 동시에 객체를 옮길 때, 각 스레드가 옮길 객체들을 위한 작은 메모리 공간(승격 버퍼)을 따로 예약하게 됩니다. 이 때문에 큰 메모리 공간이 여러 조각으로 나뉘어 사용되는데, 이를 "메모리 단편화"라고 합니다. 단편화가 심해지면 새로운 객체를 위한 연속된 큰 공간을 찾기 어려워질 수 있습니다. 그래서 단편화를 줄이려면, 가비지 컬렉션에 참여하는 스레드 수를 줄이거나, 노년 영역(오래된 객체들을 저장하는 공간)의 크기를 늘리면 됩니다.
메모리가 여러 조각으로 나뉘면, 전체 용량은 충분해도 연속된 큰 공간이 없어서 큰 객체를 할당하기 어려워지고, 그로 인해 사용 가능한 메모리가 낭비될 수 있습니다.
Arrangement of Generations in Parallel Collectors
The arrangement of the generations is different in the parallel collector.
병렬 수집기에서는 세대의 배열이 다릅니다.
Parallel Collector Ergonomics
When the parallel collector is selected by using -XX:+UseParallelGC, it enables a method of automatic tuning that allows you to specify behaviors instead of generation sizes and other low-level tuning details.
자동 조정 방식이란?
자동 조정 방식은 사용자가 메모리 영역의 크기나 기타 복잡한 튜닝 세부 사항을 직접 설정하는 대신, 원하는 동작이나 성능 목표(예: 짧은 중단 시간, 높은 처리량 등)를 지정하면, JVM이 내부적으로 최적의 설정을 자동으로 조정하는 방법을 의미합니다.
Options to Specify Parallel Collector Behaviors
병렬 수집기 동작을 지정하기 위한 옵션
You can specify maximum garbage collection pause time, throughput, and footprint (heap size).
최대 가비지 컬렉션 일시 중단 시간, 처리량 및 메모리 사용량(힙 크기)을 지정할 수 있습니다.
- Maximum garbage collection pause time: The maximum pause time goal is specified with the command-line option -XX:MaxGCPauseMillis=<N>. This is interpreted as a hint that pause times of <N> milliseconds or less are desired; by default, no maximum pause- time goal. If a pause-time goal is specified, the heap size and other parameters related to garbage collection are adjusted in an attempt to keep garbage collection pauses shorter than the specified value; however, the desired pause-time goal may not always be met. These adjustments may cause the garbage collector to reduce the overall throughput of the application.
- Throughput: The throughput goal is measured in terms of the time spent doing garbage collection versus the time spent outside of garbage collection, referred to as application time. The goal is specified by the command-line option -XX:GCTimeRatio=<N>, which sets the ratio of garbage collection time to application time to 1 / (1 + <N>).
- For example, -XX:GCTimeRatio=19 sets a goal of 1/20 or 5% of the total time in garbage collection. The default value is 99, resulting in a goal of 1% of the time in garbage collection.
- Footprint: The maximum heap footprint is specified using the option -Xmx<N>. In addition, the collector has an implicit goal of minimizing the size of the heap as long as the other goals are being met.
최대 가비지 컬렉션 일시 중단 시간: 최대 일시 중단 시간 목표는 명령줄 옵션 -XX:MaxGCPauseMillis=<N>으로 지정됩니다. 이는 <N> 밀리초 이하의 일시 중단 시간을 원한다는 힌트로 해석됩니다; 기본적으로 최대 일시 중단 시간 목표는 없습니다. 만약 일시 중단 시간 목표가 지정되면, 힙 크기 및 가비지 컬렉션과 관련된 다른 매개변수가 지정된 값보다 짧은 가비지 컬렉션 일시 중단 시간을 유지하기 위해 조정되지만, 원하는 일시 중단 시간 목표를 항상 만족하는 것은 아닙니다. 이러한 조정은 가비지 수집기가 애플리케이션의 전체 처리량을 줄이게 만들 수 있습니다.
처리량: 처리량 목표는 가비지 컬렉션에 소비되는 시간과 가비지 컬렉션 외의 시간(애플리케이션 시간) 대비로 측정됩니다. 이 목표는 명령줄 옵션 -XX:GCTimeRatio=<N>으로 지정되며, 이 옵션은 가비지 컬렉션 시간과 애플리케이션 시간의 비율을 1 / (1 + <N>)로 설정합니다. 예를 들어, -XX:GCTimeRatio=19는 전체 시간 중 1/20, 즉 5%를 가비지 컬렉션에 할당하는 목표를 설정합니다. 기본값은 99로, 이는 전체 시간의 1%를 가비지 컬렉션에 할당하는 목표를 설정합니다.
메모리 사용량: 최대 힙 사용량은 옵션 -Xmx<N>을 사용하여 지정됩니다. 또한, 수집기는 다른 목표들이 충족되는 한 힙의 크기를 최소화하는 암묵적인 목표를 가지고 있습니다.
직렬 수집기와 마찬가지로 병렬 수집기의 동작을 조정할 때 가비지 컬렉터의 일시 중단, 처리량, 메모리 사용량(힙 크기)를 설정할 수 있습니다.
Priority of Parallel Collector Goals
The goals are maximum pause-time goal, throughput goal, and minimum footprint goal, and goals are addressed in that order:
The maximum pause-time goal is met first. Only after it's met is the throughput goal addressed. Similarly, only after the first two goals have been met is the footprint goal considered.
목표는 최대 일시 중단 시간 목표, 처리량 목표, 그리고 최소 footprint(메모리 사용량, 힙의 크기) 목표이며, 이 목표들은 그 순서대로 다뤄집니다.
먼저 최대 일시 중단 시간 목표가 달성됩니다. 그 목표가 달성된 후에야 처리량 목표가 다뤄지고, 마찬가지로 처음 두 목표가 달성된 후에야 최소 footprint(메모리 사용량, 힙의 크기) 목표가 고려됩니다.
Parallel Collector Generation Size Adjustments
Statistics such as average pause time kept by the collector are updated at the end of each collection.
The tests to determine if the goals have been met are then made and any needed adjustments to the size of a generation is made. The exception is that explicit garbage collections, for example, calls to System.gc()are ignored in terms of keeping statistics and making adjustments to the sizes of generations.
Growing and shrinking the size of a generation is done by increments that are a fixed percentage of the size of the generation so that a generation steps up or down toward its desired size. Growing and shrinking are done at different rates. By default, a generation grows in increments of 20% and shrinks in increments of 5%. The percentage for growing is controlled by the command-line option -XX:YoungGenerationSizeIncrement=<Y> for the young generation and -XX:TenuredGenerationSizeIncrement=<T> for the old generation. The percentage by which a generation shrinks is adjusted by the command-line flag -XX:AdaptiveSizeDecrementScaleFactor=<D>. If the growth increment is X%, then the decrement for shrinking is X/D%.
각 컬렉션이 끝날 때, 가비지 수집기가 기록한 평균 일시 중단 시간과 같은 통계가 갱신됩니다. 그 후, 목표가 달성되었는지 확인하는 테스트가 진행되고, 필요에 따라 세대의 크기를 조정합니다. 단, 명시적 가비지 컬렉션(예를 들어, System.gc() 호출)은 통계 기록이나 세대 크기 조정에 반영되지 않습니다.
세대의 크기를 늘리거나 줄이는 작업은 해당 세대 크기의 고정된 비율로 이루어져, 세대가 원하는 크기에 점진적으로 접근하도록 합니다. 늘어나는 비율과 줄어드는 비율은 서로 다르게 적용되는데, 기본적으로 세대는 20%씩 증가하고 5%씩 감소합니다. 젊은 세대의 증분 비율은 명령줄 옵션 -XX:YoungGenerationSizeIncrement=<Y>로, 노년 세대의 증분 비율은 -XX:TenuredGenerationSizeIncrement=<T>로 제어됩니다. 세대가 줄어드는 비율은 명령줄 플래그 -XX:AdaptiveSizeDecrementScaleFactor=<D>에 의해 조정되며, 만약 증가 증분이 X%라면 감소 증분은 X/D%가 됩니다.
이 부분은 가비지 컬렉션이 끝날 때마다 평균 일시 중단 시간 같은 통계를 업데이트한 후, 설정한 목표(일시 중단 시간, 처리량, 메모리 footprint)가 달성되었는지 확인하고, 필요하면 세대(젊은 세대와 노년 세대)의 크기를 조정하는 과정을 설명합니다. 단, 명시적으로 호출한 가비지 컬렉션(System.gc() 등)은 이러한 통계 업데이트나 크기 조정에 반영되지 않습니다. 또한, 세대 크기를 조정할 때는 한 번에 전체 크기의 일정 비율만큼만 늘리거나 줄여서 점진적으로 원하는 크기에 도달하도록 하는데, 기본적으로 세대는 20%씩 커지고 5%씩 작아지도록 설정되어 있으며, 이 비율은 명령줄 옵션을 통해 조정할 수 있도록 되어 있다는 뜻입니다.
If the collector decides to grow a generation at startup, then there's a supplemental percentage is added to the increment. This supplement decays with the number of collections and has no long-term effect. The intent of the supplement is to increase startup performance. There isn't supplement to the percentage for shrinking.
If the maximum pause-time goal isn't being met, then the size of only one generation is shrunk at a time. If the pause times of both generations are above the goal, then the size of the generation with the larger pause time is shrunk first.
If the throughput goal isn't being met, then the sizes of both generations are increased. Each is increased in proportion to its respective contribution to the total garbage collection time. For example, if the garbage collection time of the young generation is 25% of the total collection time and if a full increment of the young generation would be by 20%, then the young generation would be increased by 5%.
만약 가비지 컬렉터가 시작 시에 세대를 확장하기로 결정하면, 증분에 보조 백분율이 추가된다. 이 보조치는 컬렉션 횟수에 따라 감소하며 장기적인 영향은 없다. 보조치의 의도는 시작 성능을 향상시키기 위함이다. 축소를 위한 백분율에는 보조치가 없다.
만약 최대 일시 중단 시간 목표가 달성되지 않는다면, 한 번에 오직 하나의 세대 크기만 축소된다. 만약 두 세대의 일시 중단 시간이 모두 목표를 초과한다면, 일시 중단 시간이 더 큰 세대의 크기를 먼저 축소한다.
만약 처리량 목표가 달성되지 않는다면, 두 세대의 크기를 모두 증가시킨다. 각각은 전체 가비지 컬렉션 시간에 대한 해당 세대의 기여도에 비례하여 증가된다. 예를 들어, 만약 젊은 세대의 가비지 컬렉션 시간이 전체 컬렉션 시간의 25%를 차지하고, 젊은 세대의 완전한 증분이 20%라면, 젊은 세대는 5% 증가된다.
이 시스템은 최대 일시 중단 시간을 우선으로 맞추고, 그 다음으로 처리량과 메모리 사용량 목표를 달성하기 위해 힙의 각 세대 크기를 점진적으로 조정합니다.
Parallel Collector Default Heap Size
Unless the initial and maximum heap sizes are specified on the command line, they're calculated based on the amount of memory on the machine. The default maximum heap size is one-fourth of the physical memory while the initial heap size is 1/64th of physical memory. The maximum amount of space allocated to the young generation is one third of the total heap size.
초기 힙 크기와 최대 힙 크기가 명령줄에서 지정되지 않은 경우, 이들은 머신의 메모리 양을 바탕으로 계산됩니다. 기본 최대 힙 크기는 물리적 메모리의 1/4이고, 초기 힙 크기는 물리적 메모리의 1/64입니다. 젊은 세대에 할당되는 최대 공간은 전체 힙 크기의 1/3입니다.
Specification of Parallel Collector Initial and Maximum Heap Sizes
You can specify the minimum and maximum heap sizes using the options -Xms (minimum heap size) and -Xmx (maximum heap size).
If you know how much heap your application needs to work well, then you can set -Xms and -Xmx to the same value. If you don't know, then the JVM will start by using the initial heap size and then growing the Java heap until it finds a balance between heap usage and performance.
Other parameters and options can affect these defaults. To verify your default values, use the -XX:+PrintFlagsFinal option and look for -XX:MaxHeapSize in the output. For example, on Linux you can run the following:
java -XX:+PrintFlagsFinal <GC options> -version | grep MaxHeapSize
최소 힙 크기와 최대 힙 크기는 -Xms(최소 힙 크기)와 -Xmx(최대 힙 크기) 옵션을 사용하여 지정할 수 있습니다.
애플리케이션이 원활하게 작동하는 데 필요한 힙 크기를 알고 있다면, -Xms와 -Xmx를 동일한 값으로 설정할 수 있습니다.
모른다면, JVM은 초기 힙 크기를 사용하여 시작한 후, 힙 사용량과 성능 간의 균형을 찾을 때까지 Java 힙을 확장합니다.
다른 매개변수와 옵션들이 이러한 기본값에 영향을 줄 수 있습니다. 기본값을 확인하려면 -XX:+PrintFlagsFinal 옵션을 사용하고 출력 결과에서 -XX:MaxHeapSize를 찾아보십시오. 예를 들어, Linux에서는 다음과 같이 실행할 수 있습니다.
Excessive Parallel Collector Time and OutOfMemoryError
The parallel collector throws an OutOfMemoryError if too much time is being spent in garbage collection (GC).
If more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, then an OutOfMemoryError, is thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.
병렬 수집기는 가비지 컬렉션(GC)에 너무 많은 시간이 소요될 경우 OutOfMemoryError를 발생시킵니다.
전체 시간의 98% 이상이 가비지 컬렉션에 사용되고, 힙의 2% 미만만 회수된다면 OutOfMemoryError가 발생합니다. 이 기능은 힙이 너무 작아서 거의 진전이 없거나 전혀 진전이 이루어지지 않는 상황에서 애플리케이션이 장기간 실행되는 것을 방지하기 위해 설계되었습니다. 필요하다면, 이 기능은 명령줄에 -XX:-UseGCOverheadLimit 옵션을 추가하여 비활성화할 수 있습니다.
Parallel Collector Measurements
The verbose garbage collector output from the parallel collector is essentially the same as that from the serial collector.
병렬 수집기에서 나오는 자세한 가비지 컬렉터 출력은 본질적으로 직렬 수집기에서 나오는 것과 동일합니다.
'공식문서' 카테고리의 다른 글
[Spring Docs] Choosing an Approach for JDBC Database Access (0) | 2025.03.26 |
---|---|
[Spring Docs] DAO Support (0) | 2025.03.25 |
[Spring Docs] Transaction Managment #5 (0) | 2025.03.21 |
[Spring Docs] Programmatic Transaction Management #4 (0) | 2025.03.20 |
[Spring Docs] Transaction Management #3 (0) | 2025.03.19 |