4

使用 VisualVM,我在 JBoss 服务器上观察到以下堆使用情况:

VisualVm 的 Heap 使用截图

服务器使用以下(相关)JVM 选项启动:

-Xrs -Xms3072m -Xmx3072m -XX:MaxPermSize=512m -XX:+UseParallelOldGC -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000

我们目前还启用了 GC 日志记录:

-XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:log\gc.log

基本上我对观察到的模式很满意,因为看起来我们没有任何内存泄漏(这种模式会在几天内重复出现)。

但是我想知道是否有优化空间?

首先,我不明白为什么当堆使用量达到大约 2GB 时垃圾收集已经开始了?在我看来,它可能会在以后启动,因为堆将有 3GB 可用?

此外,我会对有关观察到的堆使用模式和使用的 JVM 选项的提示感兴趣:

  • 观察到的模式是否允许我得出关于使用的 GC 策略 (UseParallelOldGC) 的结论?这个策略是正确的,还是应该考虑到观察到的堆使用情况尝试使用另一种策略?

  • 我可以优化 GC 过程,以便使用完整的堆大小(3GB)吗?

  • 现在看起来完整的 3GB 从未使用过,我应该将 Xms/Xmx 减少到 2.5GB 吗?

  • 我是否缺少任何明显的 GC 优化?喜欢调整 -XX:NewSize 还是 -XX:NewRatio?

  • 还有什么其他的提示吗?

谢谢!

4

1 回答 1

7

我会说屏幕截图中的 GC 行为看起来很“正常”。

您通常希望在堆空间太满之前触发主要收集,否则很容易遇到 OutOfMemoryError,这取决于许多场景。

此外,您是否知道 Java 的堆空间被划分为新(伊甸园)、当前(幸存者)和旧(终身)对象的不同区域?

这个答案提供了关于这个主题的一些很好的信息,所以我不会在这里重复:

java内存池是怎么划分的?

基本上,堆的每个区域都会触发自己的集合。伊甸园空间通常被经常收集,并且“快速”幸存者和终身空间通常更大并且需要更长的时间来收集。

你能根据上图减少堆大小吗?

是的。但是,您当前的配置允许您的应用程序有一些喘息的空间,如果它可能会遇到更繁忙的时期或负载峰值。

你能优化GC吗?

是的,但没有神奇的设置。第一个问题是你真的需要吗?如果您的应用程序只是一个非交互式“处理器”,我真的不会打扰。如果您确实需要低暂停应用程序,那么可以进行一些调整。权衡通常是您需要更多资源才能获得相同的结果。

我的经验是,当负载增加时,低暂停 JVM 配置有一个非常明显的下降点。如果您的应用程序通常相当空闲,但您希望在调用它时得到“快速”响应,那么低暂停可能是合适的。在繁忙的系统中,流量/负载达到峰值时,您可能更喜欢更传统的方法。

概括

在任何情况下,都不要试图进行任意更改以“改进”您的配置。对您的方法保持科学和专业。

如果您没有可用的生产指标,请考虑使用Apache JMeter之类的工具来构建负载测试场景,以模拟应用程序上的典型实时负载、增加的负载(例如 10%、20% 或 50% 等)和间歇性负载高峰负荷。

为 GC 和应用程序使用指标,至少测量:

  • 平均吞吐量。
  • 峰值吞吐量。
  • 平均负载(CPU 和内存)。
  • 高峰负荷。
  • 应用程序暂停时间(总暂停和个别暂停)。
  • 执行收集所花费的时间。
  • 可靠性(OOME 等)。

一旦您对使用当前配置记录了应用程序性能的准确基准感到高兴,那么您才应该开始进行任何更改。

显然,记录您的配置及其指标。记录任何更改,然后执行相同的基准测试。然后,您将能够看到任何性能增益(或损失)以及可能适用的任何权衡。

以下是 Oracle 关于该主题的进一步阅读,可帮助您入门:

Java SE 6 虚拟机垃圾收集调优

于 2012-10-24T10:39:13.013 回答