垃圾回收器在执行某些垃圾回收任务时会暂停所有应用程序线程. 这些暂停有时被称为 Stop-The-World 暂停, 因此尽可能避免这种情况是 GC 调优的主要目标, 因为它们会对 Java 应用程序的性能产生巨大影响.
调整堆大小
垃圾回收调优的第一步是调整堆的大小. 这是因为如果堆太小, 则会发生太多的 GC 以回收内存, 这会降低整体应用程序吞吐量, 如果堆太大, 那么 GC 发生概率会少, 一旦发生 GC 则需要很长时间, 这样你的应用的响应时间指标就会受到影响. 并行收集器特别容易受到此问题的影响, 因此如果您需要大堆并且暂停时间较短, 那么您应该尝试使用 G1GC 收集器.
旁注: 因为 Java 9 和 Shenandoah 垃圾收集器在撰写本文时仍被视为 "实验性" 时, 不推荐使用并发标记扫描 (CMS) 收集器. 因此, 如果您正在运行在线交互式应用程序, 那么 G1GC 应该是您的默认选择, 如果您正在运行脱机批处理应用程序, 那么并行收集器应该是您的首选.
堆的大小由两个值控制: 使用 ms 标志指定的初始值和使用 mx 标志指定的最大值.
-Xms1g -Xmx8g
堆的初始和最大大小允许 JVM 根据工作负载自动调整堆大小. 如果 JVM 遇到内存压力并且观察到 GC 执行过多, 它会不断增加堆, 直到内存压力消失, 或直到堆达到其最大大小. 如果内存压力很低, JVM 还可以通过缩小堆大小来决定减少暂停时间. 这个过程称为自适应大小调整, 它不仅可以调整堆的整体大小, 还可以调整年轻代和老代的大小和比例.
如果您花时间精细调整应用程序的 GC 行为和大小, 则可以选择关闭自适应大小调整. 这可以节省 JVM 计算堆大小所需的一小段时间. 您可以通过将标志设置 UseAdaptiveSizePolicy 为 false 来执行此操作.
-XX:-UseAdaptiveSizePolicy
此外, 将初始堆大小设置为与最大堆大小相同的值或将初始新 gen 大小设置为与最大新 gen 大小相同的值只能关闭大小自适应调整行为的一部分.
强烈建议的设置最大堆大小的准则是最大堆大小不应超过计算机上的物理内存量. 如果您运行多个 JVM, 则最大堆大小的总和不应超过计算机的物理内存.
设置最大堆大小的更一般建议是: 在完整 GC 之后堆占用大约 30%, 要计算此值, 您可以在 GC 日志中查找完整 GC 发生的条目, 并观察 GC 完成时使用的内存量. 或者, 您可以运行应用程序, 直到它达到稳定状态, 然后使用 jconsole 或强制使用完整的 GC jcmd.
调整 GC 性能
如果启用了自适应大小调整, 则可以使用 MaxGCPauseMillis 标志来调整 GC 行为, 此标志设置最大 GC 暂停时间的目标, 当与 Parallel 收集器一起使用时, JVM 将调整年轻一代和老一代的大小, 以便尝试达到目标, 然后它将调整堆的大小, 以便在 GC 中花费的时间不超过某个值, 默认情况下为 1%.
G1GC 的目标之一是它只需要很少的调整, 因此, 在 G1GC 中, 一个调整参数 MaxGCPauseMillis 执行以下所有优化, 以尝试实现指定的暂停时间目标:
调整堆的大小
更快开始后台处理,
调整阈值: 对象成为老生代的对象的时间期限,
调整在混合 GC 循环期间处理的旧区域数.
在 G1GC 中, 标志的默认值为 200 ms. 虽然你可能想把它设置成一个非常小的 20 毫秒, 但请注意, 为了达到这个目的, 垃圾收集器会将年轻一代收缩到一个非常小的尺寸并收集较少的老一代, 这最终会导致老一代垃圾过多的情况, 系统必须执行完整的 GC, 这是不可取的.
修复并发模式故障
G1GC 是一个并发收集器, 这意味着当应用程序线程仍在运行时, 垃圾收集进程的某些阶段可以并发运行, 并且由于正在运行的应用程序可以继续产生垃圾, 我们可能会遇到应用程序耗尽老生代内存而垃圾收集器仍在垃圾收集过程中的情况. 换句话说, 正在运行的应用程序生成的垃圾比它可以清理的速度快. 这种情况称为并发模式故障, 失效故障或疏散故障, 具体取决于故障发生的时间. 如果您在 GC 日志中看到很多这些错误, 解决方案是增加堆的大小, 更早地启动 G1 后台处理, 或者通过使用更多后台线程来加速 GC 处理.
要更频繁地执行 G1 后台活动, 您可以降低触发 G1 循环的阈值. 这是通过减少 InitiatingHeapOccupancyPercent 标志的值来实现的.
-XX:InitiatingHeapOccupancyPercent=45
默认情况下, 此标志设置为 45. 这意味着当堆填充 45%时会触发 GC 循环. 减少此值意味着 GC 会更早且更频繁地触发. 但应注意的是, 该值不会设置为太低而导致 GC 过于频繁发生.
要增加后台线程数, 请使用该 ConcGCThreads 标志.
-XX:ConcGCThreads=4
此标志的默认值设置为 ParallelGCThreadss 加 2 除以 4. 只要计算机上有足够的 CPU 可用, 就可以增加此值而不会导致任何性能损失.
如果调整堆大小并调整收集器对您不起作用, 那么您可以尝试另一个收集器. 如果你仍然没有取得好成绩, 那么你需要考虑调整应用程序代码本身.
来源: http://www.jianshu.com/p/211bda16781d