SRC Parallel Garbage Collector

本文介绍如何使用并行垃圾回收器(Throughput Collector)来提高应用程序性能,尤其是在多处理器环境中。通过多线程进行小回收可以减少应用程序的串行执行时间,并探讨了不同处理器数量下并行垃圾回收器的表现。

-XX:+UseParallelGC


4.1When to Use the Throughput Collector

Use the throughput collector when you want to improve the performance of your application with larger numbers of processors. In the default collector garbage collection is done by one thread, and therefore garbage collection adds to the serial execution time of the application. The throughput collector uses multiple threads to execute a minor collection and so reduces the serial execution time of the application. A typical situation is one in which the application has a large number of threads allocating objects. In such an application it is often the case that a large younggeneration is needed.

4.2 The Throughput Collector

The throughput collector is a generational collector similar to the default collector but with multiple threads used to do the minor collection. The major collections are essentially the same as with the default collector. By default on a host with N CPUs, the throughput collector uses N garbage collector threads in the collection. The number of garbage collector threads can be controlled with a command line option (see below). On a host with 1 CPU the throughput collector will likely not perform as well as the default collector because of the additional overhead for the parallel execution (e.g., synchronization costs). On a host with 2 CPUs the throughput collector generally performs as well as the default garbage collector and a reduction in the minor garbage collector pause times can be expected on hosts with more than 2 CPUs.

The throughput collector can be enabled by using command line flag -XX:+ UseParallelGC . The number of garbage collector threads can be controlled with the ParallelGCThreads command line option ( -XX:ParallelGCThreads=<desired number>). The size of the heap needed with the throughput collector to first order is the same as with the default collector. Turning on the throughput collector should just make the minor collection pauses shorter. Because there are multiple garbage collector threads participating in the minor collection there is a small possibility of fragmentation due to promotions from the young generation to the tenured generation during the collection. Each garbage collection thread reserves a part of the tenured 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 will reduce this fragmentation effect as will increasing the size of the tenured generation.

4.2.1 Adaptive Sizing

A feature available with the throughput collector in the J2SE platform, version 1.4.1 and later releases is the use of adaptive sizing ( -XX:+ UseAdaptiveSizePolicy ), which is on by default. Adaptive sizing keeps statistics about garbage collection times, allocation rates, and the free space in the heap after a collection. These statistics are used to make decisions regarding changes to the sizes of the young generation and tenured generation so as to best fit the behavior of the application. Use the command line option -verbose:gc to see the resulting sizes of the heap.

4.2.2 AggressiveHeap

The -XX:+ AggressiveHeap option inspects the machine resources (size of memory and number of processors) and attempts to set various parameters to be optimal for long-running, memory allocation-intensive jobs. It was originally intended for machines with large amounts of memory and a large number of CPUs, but in the J2SE platform, version 1.4.1 and later it has shown itself to be useful even on four processor machines. With this option the throughput collector ( -XX:+UseParallelGC ) is used along with adaptive sizing ( -XX:+UseAdaptiveSizePolicy ). The physical memory on the machines must be at least 256MB before AggressiveHeap can be used. The size of the initial heap is calculated based on the size of the physical memory and attempts to make maximal use of the physical memory for the heap (i.e., the algorithms attempt to use heaps nearly as large as the total physical memory).

4.2.3 Measurements with the Throughput Collector

The verbose garbage collector output is the same for the throughput collector as with the default collector.


Implementation of -XX:+UseAdaptiveSizePolicy Used by Parallel Garbage Collector Changed

The implementation of -XX:+UseAdaptiveSizePolicy used by default with the -XX:+UseParallelGC garbage collector has changed to consider three goals:
  • a desired maximum GC pause goal
  • a desired application throughput goal
  • minimum footprint

The implementation checks (in this order):

  1. If the GC pause time is greater than the pause time goal then reduce the generations sizes to better attain the goal.
  2. If the pause time goal is being met then consider the application's throughput goal. If the application's throughput goal is not being met, then increase the sizes of the generations to better attain the goal.
  3. If both the pause time goal and the throughput goal are being met, then the size of the generations are decreased to reduce footprint.

Flags

-XX:MaxGCPauseMillis=nnn
A hint to the virtual machine that pause times of nnn milliseconds or less are desired. The VM will adjust the java heap size and other GC-related parameters in an attempt to keep GC-induced pauses shorter than nnnmilliseconds. Note that this may cause the VM to reduce overall throughput, and in some cases the VM will not be able to meet the desired pause time goal.

By default there is no pause time goal. There are definite limitations on how well a pause time goal can be met. The pause time for a GC depends on the amount of live data in the heap. The minor and major collections depend in different ways on the amount of live data. This parameter should be used with caution. A value that is too small will cause the system to spend an excessive amount of time doing garbage collection.

-XX:GCTimeRatio=nnn
A hint to the virtual machine that it's desirable that not more than 1 / (1 + nnn) of the application execution time be spent in the collector.

For example -XX:GCTimeRatio=19 sets a goal of 5% of the total time for GC and throughput goal of 95%. That is, the application should get 19 times as much time as the collector.

By default the value is 99, meaning the application should get at least 99 times as much time as the collector. That is, the collector should run for not more than 1% of the total time. This was selected as a good choice for server applications. A value that is too high will cause the size of the heap to grow to its maximum.

Suggested strategy

Do not choose a maximum value for the heap unless you know that the heap is greater than the default maximum heap size. Choose a throughput goal that is sufficient for your application.

In an ideal situation the heap will grow to a value (less than the maximum) that will support the chosen throughput goal.

If the heap grows to its maximum, the throughput cannot be met within that maximum. Set the maximum heap as large as you can, but no larger than the size of physical memory on the platform, and execute the application again. If the throughput goal can still not be met, then it is too high for the available memory on the platform.

If the throughput goal can be met but there are pauses that are too long, select a pause time goal. This will likely mean that your throughput goal will not be met, so choose values that are an acceptable compromise for the application.



JVM垃圾回收器(GC)抖动(thrashing)是指JVM频繁进行垃圾回收,但每次回收释放的内存却非常有限,这通常会导致系统性能严重下降。在某些情况下,GC抖动可能会导致守护进程(daemon)超时甚至被操作系统终止(expiration),因为JVM长时间无法响应外部请求或心跳检测失败。 ### GC抖动的原因 1. **堆内存不足**:JVM堆内存配置过小,无法容纳程序运行时所需的对象,导致频繁GC。 2. **内存泄漏**:程序中存在未释放的无用对象引用,导致老年代(Old Generation)不断增长,最终触发Full GC。 3. **对象生命周期不合理**:大量短生命周期对象晋升到老年代(例如由于Survivor空间不足),导致老年代快速填满。 4. **GC算法选择不当**:不同的GC算法对不同类型的应用表现不同。例如,CMS(Concurrent Mark-Sweep)适用于低延迟场景,而G1(Garbage-First)则更适用于大堆内存管理。 5. **元空间(Metaspace)溢出**:类加载过多,导致元空间不断扩展,触发频繁的元空间GC。 ### GC抖动的表现 - **GC频率显著增加**:通过JVM监控工具(如JVisualVM、JConsole或Prometheus+Grafana)可以观察到GC事件频繁发生。 - **GC停顿时间增长**:尤其是Full GC的停顿时间显著增加,影响系统响应能力。 - **CPU使用率升高**:GC线程频繁运行,占用大量CPU资源。 - **守护进程超时**:例如Kubernetes中的Pod因健康检查失败而被重启,或ZooKeeper中的会话超时。 ### 解决方案 #### 1. 增加堆内存 适当增加JVM堆内存大小,尤其是老年代的大小,可以减少Full GC的频率。可以通过以下JVM参数调整堆大小: ```bash -Xms4g -Xmx8g -XX:NewRatio=2 ``` 上述配置将堆初始大小设为4GB,最大扩展到8GB,新生代与老年代的比例为1:2[^1]。 #### 2. 优化GC策略 根据应用类型选择合适的垃圾回收器: - **吞吐量优先**:Parallel Scavenge + Parallel Old - **低延迟优先**:G1 GC 或 ZGC 启用G1 GC的示例参数: ```bash -XX:+UseG1GC -XX:MaxGCPauseMillis=200 ``` 该配置启用G1垃圾回收器,并设置最大GC停顿时间为200毫秒[^1]。 #### 3. 检查内存泄漏 使用工具如Eclipse MAT(Memory Analyzer)分析堆转储(heap dump),查找未被释放的对象路径,尤其是`ClassLoader`、`ThreadLocal`、静态集合等常见泄漏源。 #### 4. 调整对象生命周期 减少短生命周期对象的晋升,可以通过调整Survivor空间大小或Tenuring阈值来实现: ```bash -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 ``` #### 5. 监控和调优元空间 限制元空间最大使用量,防止其无限制增长: ```bash -XX:MaxMetaspaceSize=512m ``` 同时,可以通过`jstat -gc`命令监控元空间使用情况。 #### 6. 避免守护进程超时 在容器环境中(如Kubernetes),应合理设置健康检查(liveness/readiness probes)的超时时间和重试次数,避免因短暂GC停顿导致进程被误杀。 --- ### 示例:G1 GC日志分析片段 ```log 2024-07-01T12:00:00.000+0800: [GC pause (G1 Evacuation Pause) (young), 0.0561234 secs] [Parallel Time: 52.3 ms, GC Workers: 8] [Marking Phase: 12.4 ms] [Evacuation: 35.2 ms] [Other: 4.7 ms] ``` 上述日志显示一次G1年轻代GC耗时约56毫秒,属于正常范围。若频繁出现超过200毫秒的GC事件,则应引起关注。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值