一:jvm性能指标吞吐量以及用户停顿时间解释。
二:垃圾回收器的选择。
三:垃圾回收器在jvm中的配置。
四:jvm中常用的gc算法。
一:jvm性能指标吞吐量以及用户停顿时间解释。
在 JVM 调优和垃圾回收器选择中,吞吐量(Throughput) 和 用户停顿时间(Pause Time) 是两个非常重要的性能指标。它们分别反映了垃圾回收器在处理垃圾回收任务时对应用程序性能的影响。以下是对这两个概念的详细解释:
1. 吞吐量(Throughput)
含义:吞吐量是指应用程序在运行过程中,实际执行业务逻辑的时间与总运行时间的比值。它反映了应用程序在垃圾回收期间的效率。
计算公式:
- 高吞吐量:表示应用程序在大部分时间内都在执行业务逻辑,垃圾回收所占用的时间较少。这种情况下,应用程序的性能较高,适合对性能要求较高的场景。
- 低吞吐量:表示垃圾回收占用的时间较多,应用程序的实际运行时间较短。这种情况下,应用程序的性能会受到较大影响。
应用场景:
- 如果你的应用程序对性能要求较高,且用户对停顿时间不太敏感(例如后台数据处理任务),则应优先选择高吞吐量的垃圾回收器。
2. 用户停顿时间(Pause Time)
含义:用户停顿时间是指垃圾回收器在回收内存时,导致应用程序线程暂停的时间。垃圾回收器在执行某些操作(如 Full GC 或 Major GC)时,会暂停应用程序的执行,这种暂停被称为 Stop-The-World (STW)。
特点:
- 短停顿时间:表示垃圾回收器在执行回收任务时,对应用程序的暂停时间较短。这种情况下,用户体验较好,适合对响应时间敏感的应用。
- 长停顿时间:表示垃圾回收器在执行回收任务时,暂停应用程序的时间较长。这种情况下,用户体验可能会受到影响。
应用场景:
- 如果你的应用程序对响应时间要求较高(例如在线交易系统、实时交互系统),则应优先选择低停顿时间的垃圾回收器。
二:垃圾回收器的选择
根据吞吐量和停顿时间的需求,可以选择不同的垃圾回收器:
1 Serial 垃圾收集器
- 特点:单线程执行垃圾回收,停顿时间较短,但吞吐量较低。
- 适用场景:适用于单核 CPU 或对吞吐量要求不高的场景。
2 Parallel Scavenge + Parallel Old 组合(JDK8默认)
- 特点:多线程执行垃圾回收,吞吐量较高,但停顿时间可能较长。
- 适用场景:适用于多核 CPU,且对吞吐量要求较高的场景(如后台数据处理)。
3 ParNew + CMS 组合
- 特点:多线程执行垃圾回收,停顿时间较短,但吞吐量较低。
- 适用场景:适用于多核 CPU,且对停顿时间要求较高的场景(如在线交易系统)。
4 G1 垃圾收集器
- 特点:分代收集与并发收集结合,停顿时间可控,吞吐量也较高。
- 适用场景:适用于多核 CPU,且对停顿时间和吞吐量都有较高要求的场景(如大型企业级应用)。
5. 总结
- 吞吐量:反映应用程序在垃圾回收期间的实际运行效率,适合对性能要求较高的场景。
- 用户停顿时间:反映垃圾回收对应用程序的暂停时间,适合对响应时间敏感的场景。
- 垃圾回收器选择:根据应用程序的需求(吞吐量或停顿时间优先)和硬件环境(CPU 核数)选择合适的垃圾回收器。
在实际调优中,需要根据具体的应用场景和性能要求,综合考虑吞吐量和停顿时间的平衡。
三:垃圾回收器在jvm中的配置。
在 Java 应用程序中,配置垃圾回收器及其相关参数是 JVM 调优的重要部分。以下是如何配置不同垃圾回收器及其常用参数的详细说明:
1. 配置垃圾回收器
垃圾回收器的选择和配置通过 JVM 启动参数完成。以下是一些常见垃圾回收器的配置方法:
1.1 Serial 垃圾收集器
适用于单核 CPU 或小型应用,吞吐量较低,但停顿时间较短。
-XX:+UseSerialGC
1.2 Parallel Scavenge + Parallel Old 组合
适用于多核 CPU,吞吐量较高,适合对吞吐量要求较高的场景。
-XX:+UseParallelGC # 新生代使用 Parallel Scavenge
-XX:+UseParallelOldGC # 老年代使用 Parallel Old
1.3 ParNew + CMS 组合
适用于多核 CPU,停顿时间较短,适合对响应时间敏感的场景。
-XX:+UseParNewGC # 新生代使用 ParNew
-XX:+UseConcMarkSweepGC # 老年代使用 CMS
1.4 G1 垃圾收集器
适用于多核 CPU,兼顾吞吐量和停顿时间,适合大堆内存(6GB 以上)的场景。
-XX:+UseG1GC
1.5 ZGC 或 Shenandoah
适用于超大堆内存(TB 级别)和低延迟需求的场景。
-XX:+UseZGC # 使用 ZGC
# 或
-XX:+UseShenandoahGC # 使用 Shenandoah
2. 常用垃圾回收器参数配置
2.1 调整堆内存大小
- 初始堆大小(
-Xms
):设置 JVM 启动时的堆大小。 - 最大堆大小(
-Xmx
):设置 JVM 允许的最大堆大小。 - 新生代大小(
-Xmn
):设置新生代的大小。
-Xms1024m -Xmx1024m -Xmn256m
2.2 调整新生代和老年代比例
-XX:NewRatio
:设置新生代与老年代的比例(默认值为 2)。-XX:SurvivorRatio
:设置伊甸园与幸存区的比例(默认值为 8)。
-XX:NewRatio=4 //表示新生代:老年代 = 1:4 即老年代占整个堆的4/5;默认值=2
-XX:SurvivorRatio=8 //伊甸园:幸存区=8:2-XX:NewRatio=12 //表示新生代与老年代的比例为 1:12
-XX:SurvivorRatio=11 //表示伊甸园与每个幸存区的比例为 11:1
2.3 调整垃圾回收目标
-XX:MaxGCPauseMillis
:设置垃圾回收的最大停顿时间目标(单位为毫秒)。-XX:GCTimeRatio
:设置垃圾回收的吞吐量目标(默认值为 99,表示吞吐量为 99%)。
-XX:MaxGCPauseMillis=100 -XX:GCTimeRatio=99
2.4 调整老年代回收策略
-
CMS 回收器:
-XX:CMSInitiatingOccupancyFraction
:设置老年代占用比例达到多少时触发 CMS 回收(默认值为 68%)。
-XX:CMSInitiatingOccupancyFraction=70
-
G1 回收器:
-XX:InitiatingHeapOccupancyPercent
:设置堆占用比例达到多少时触发混合垃圾回收(默认值为 45%)。-XX:G1MixedGCLiveThresholdPercent
:设置对象存活比例达到多少时触发混合垃圾回收(默认值为 85%)。
-XX:InitiatingHeapOccupancyPercent=50 -XX:G1MixedGCLiveThresholdPercent=70
2.5 调整大对象处理
-XX:PretenureSizeThreshold
:设置大对象直接进入老年代的阈值(单位为字节,默认为 0,表示关闭)。-XX:MaxTenuringThreshold
:设置对象晋升到老年代的最大年龄(默认值为 15)。
-XX:PretenureSizeThreshold=1048576 -XX:MaxTenuringThreshold=7
2.6 其他参数
-XX:+PrintGCDetails
:打印详细的垃圾回收日志。-XX:+PrintGCDateStamps
:打印垃圾回收的时间戳。-Xlog:gc*
:将垃圾回收日志输出到指定文件。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xlog:gc*:gc.log
3. 示例配置
以下是一个完整的 JVM 参数配置示例,适用于多核 CPU 和对停顿时间要求较高的场景:
-Xms1024m -Xmx1024m -Xmn256m -XX:SurvivorRatio=8 -XX:NewRatio=4
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:GCTimeRatio=99
-XX:InitiatingHeapOccupancyPercent=50 -XX:G1MixedGCLiveThresholdPercent=70
-XX:PretenureSizeThreshold=1048576 -XX:MaxTenuringThreshold=7
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xlog:gc*:gc.log
4. 总结
- 根据应用需求选择合适的垃圾回收器。
- 使用 JVM 参数调整垃圾回收器的行为,包括堆内存大小、新生代和老年代比例、停顿时间目标等。
- 使用垃圾回收日志监控和分析垃圾回收行为,根据实际情况调整参数。
通过合理的配置,可以显著提升应用程序的性能和响应能力。
四:jvm中常用的gc算法
在 Java 中,垃圾回收(GC)主要通过以下四种算法实现:标记-清除、复制、标记-整理和分代收集。以下是这些算法的详细解释:
1. 标记-清除算法(Mark-Sweep)
原理:
- 标记阶段:从根对象(如全局变量、栈中的对象)出发,遍历所有可达对象,并标记它们为存活。
- 清除阶段:遍历整个堆内存,释放未被标记的对象所占用的内存。
优点:
- 实现简单,适用于大多数场景。
缺点:
- 会产生内存碎片,可能导致后续内存分配效率降低。
- 每次清除都需要扫描整个堆,效率较低。
适用场景:
- 主要用于老年代(如 CMS 收集器)。
2. 复制算法(Copying)
原理:
- 将存活对象从“From”区复制到“To”区,然后清空“From”区。
- 新生代通常分为 Eden 区和两个 Survivor 区(S0 和 S1),当 Eden 区满时,将存活对象复制到其中一个 Survivor 区。
优点:
- 无内存碎片,内存分配高效。
缺点:
- 内存利用率低,仅使用一半的内存。
适用场景:
- 主要用于新生代(如 Serial、ParNew 收集器)。
3. 标记-整理算法(Mark-Compact)
原理:
- 标记阶段:标记所有可达对象。
- 整理阶段:将存活对象移动到堆的一端,清理边界外的空间。
优点:
- 无内存碎片,内存利用率高。
缺点:
- 移动对象成本高,可能导致较长的停顿时间。
适用场景:
- 主要用于老年代(如 Parallel Old、G1 收集器)。
4. 分代收集算法(Generational Collection)
原理:
- 将堆内存分为新生代和老年代。
- 新生代:使用复制算法,因为大多数对象生命周期短。
- 老年代:使用标记-清除或标记-整理算法,因为对象生命周期长。
优点:
- 针对不同生命周期的对象采用不同的回收策略,提高了回收效率。
缺点:
- 实现复杂,需要维护多个代的内存区域。
适用场景:
- 现代 JVM 通常采用分代收集算法,适用于大多数应用场景。
5. 引用计数算法(Reference Counting)
原理:为每个对象维护一个引用计数器,记录该对象被引用的次数。当引用计数器的值为零时,表示该对象不再被任何变量引用,可以被垃圾回收。
优缺点及适用场景
引用计数法:通过维护引用计数器来管理对象的生命周期,优点是简单高效,缺点是无法处理循环引用,且性能开销较大。
适用场景:适用于简单场景和对停顿时间要求极高的实时系统。
在 Java 中:适用于简单场景,实时系统或混合使用。引用计数法不是主流垃圾回收算法,但它的原理有助于理解垃圾回收机制。
总结
- 标记-清除算法:简单但会产生内存碎片,适用于老年代。
- 复制算法:高效但内存利用率低,适用于新生代。
- 标记-整理算法:无碎片但停顿时间长,适用于老年代。
- 分代收集算法:综合多种算法,兼顾效率和内存利用率,是现代 JVM 的主流策略。
- 引用计数法:不是主流垃圾回收算法,但它的原理有助于理解垃圾回收机制