【问题标题】:Appropriate JVM/GC tuning for 4GB JVM with 3GB cache为具有 3GB 缓存的 4GB JVM 进行适当的 JVM/GC 调整
【发布时间】:2012-02-06 21:33:22
【问题描述】:

我正在寻找合适的设置来为 Web 应用程序配置 JVM。我已经阅读了关于 old/young/perm generation 的文章,但是我在使用这些参数时遇到了麻烦。

在 4 GB 中,大约 3 GB 用于缓存(使用 EhCache 的应用缓存),因此我正在寻找考虑到这一点的最佳设置。仅供参考,缓存在应用程序的生命周期内是静态的(从磁盘加载,永不过期),但被大量使用。

我已经分析了我的应用程序,并且我已经对数据库查询、应用程序的架构、缓存大小等进行了优化... 我只是在寻找 JVM 配置建议这里。我测量了垃圾收集器的 99% 吞吐量,并且在 Full GC 运行时 6-8 秒暂停(大约每 1/2 小时一次)。

这里是当前的 JVM 参数:

-XX:+UseParallelGC -XX:+AggressiveHeap -Xms2048m -Xmx4096m
-XX:NewSize=64m -XX:PermSize=64m -XX:MaxPermSize=512m
-verbose:gc -XX:+PrintGCDetails -Xloggc:gc.log

那些参数可能已经完全关闭了,因为它们是很久以前写的......在应用程序变得那么大之前。

我使用的是 Java 1.5 64 位。

您是否看到任何可能的改进?

编辑:机器有 4 个核心。

【问题讨论】:

    标签: java optimization garbage-collection jvm jvm-arguments


    【解决方案1】:

    -XX:+UseParallel*Old*GC 应该加快多核机器上的 Full GC。

    您还可以使用不同的 NewRatio 值进行分析。您的缓存对象将存在于终身代中,因此使用 -XX:NewRatio=7 对其进行分析,然后再使用一些更高和更低的值。

    您可能无法在分析期间准确地复制实际使用情况,因此请确保在实际使用时监控 GC,然后您可以进行细微更改(例如,对幸存者空间等)并查看它们的效果。

    旧的建议是不要将 AggressiveHeap 与 Xms 和 Xmx 一起使用,我不确定这是否仍然正确。

    编辑:请告诉我们您部署在哪个操作系统/硬件平台上。

    每 30 分钟完成一次收集表明老年代已经很满了。 newRatio 的高值会以牺牲年轻一代为代价为其提供更多空间。可以给 JVM 超过 4g 还是仅限于此?

    了解您的目标/非功能性需求是什么也很有用。您想避免这些 6 / 7 秒的停顿,冒着降低吞吐量的风险,还是为了尽可能高的吞吐量,这些停顿是可接受的折衷方案?

    如果您想尽量减少停顿,请尝试 CMS 收集器,删除两者

    -XX:+UseParallelGC -XX:+UseParallelOldGC 
    

    添加

    -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
    

    使用各种 NewRatio 值对其进行概要分析,看看你的进展如何。

    CMS 收集器的一个缺点是与并行旧代收集器和串行收集器不同,它不会压缩旧代。如果老年代变得过于碎片化并且次要集合需要一次将大量对象提升到老年代,则可能会调用完整的串行集合,这可能意味着长时间的停顿。 (我曾经在 prod 中看到过这种情况,但是 IBM JVM 内存不足而不是调用压缩集合!)

    这对您来说可能不是问题 - 这取决于应用程序的性质 - 但您可以通过每晚或每周重新启动来确保不会出现这种情况。

    【讨论】:

    • 以防万一不清楚,UseParallelOldGC 与 UseParallelGC 不同。如果您使用 UseParallelOldGC,则 UseParallelGC 也已打开,因此您不需要两者。
    • 我会尽快尝试 UseParallelOldGC 和 NewRatio,谢谢。如果有人知道带有 Xms 和 Xmx 的 AggressiveHeap,请告诉我。
    • UseParallelOldGC 无效,我得到了 40s Full GC 而不是 7s :D。很奇怪(如你所说,我删除了 UseParallelGC)
    • 尝试不使用积极堆和不使用 NewSize。如果您知道您将使用 3GB 作为缓存,请将 Xms 设置为 4096m。如果你不这样做,它会在每次需要增加堆时进行 Full GC。
    • 是的,我已经删除了 AggressiveHeap 并将 Xms 设置为 4096m。我用 GCViewer 看过 gc.log 并且启动更好(没有完整的 gc)
    【解决方案2】:

    我希望您刚刚删除 -server 以防止帖子膨胀,否则您应该立即启用它。除了更长的启动时间(这对于应该运行数天的 Web 应用程序来说确实不是问题)之外,我认为除了 c2 之外没有任何理由使用任何东西。一般来说,这可以带来一些不错的性能改进。嗯,回到主题:

    遗憾的是,我能想到的最好的方法不适用于您古老的 JVM。 G1 垃圾收集器基本上是为了减少延迟而设计的。它不仅尝试总体上减少暂停,还提供一些调整参数来设置暂停目标和间隔。见this page

    有一个 java6 的实验性反向移植,但我怀疑它是否保持最新。我担心没有人会再浪费时间优化 Java 1.5 的 GC 或其他任何东西了。

    PS:还有 IBM 的 JVM,显然还有 azul systems(好吧,这不是一个严肃的提议;)),但这些显然是不可能的......只是想提一下。

    【讨论】:

    • 除非它在 ​​Windows 上运行,否则 JVM 不会在具有 >2GB RAM 的 4 核机器上默认为服务器模式吗?
    • @Paul 不知道,我不知道有任何这样的优化,但我对热点一无所知。我仍然不会在有条件的默认值上冒如此重要的标志。
    • @Paul 有趣的花絮谢谢。所以 c1 这些天基本上完全没有使用(因为热点默认为每个 64 位 cpu 的 c2) - 真的很好。
    • @PaulMedcraft 获取信息,是的,JVM 自动检测当前机器的“​​服务器类”并相应地更改 JVM 选项。这被称为“人机工程学设置”java.sun.com/performance/reference/whitepapers/… 所以不需要把 -server
    【解决方案3】:

    我会使用 Java 6 update 30 或 7 update 2、64 位,因为它们效率更高。例如他们默认使用 32 位引用。

    如果可能的话,我还会将 Ehcache 配置为使用直接内存或内存映射文件。这应该尽量减少对 GC 的影响。

    使用这些选项几乎可以消除您的堆足迹。例如我有一个应用程序,它在具有 16 GB 内存且堆大小为 6 MB 的机器上使用多达 180 GB 的内存映射文件。手动触发时,完整的 GC 最多需要 11 毫秒,而不是 GC。 ;)

    如果你想要一个简单的例子,我将一个 8 TB 的文件映射到内存中并更新它。 http://vanillajava.blogspot.com/2011/12/using-memory-mapped-file-for-huge.html

    【讨论】:

    • 切换到 Java 6 是个好主意,但这是一个重大变化,很遗憾这不是我的决定:((公司政策)
    • 关于配置EhCache,已经测试过了,但是由于应用程序的架构,缓存必须在内存中(而不是在磁盘上),否则访问时间太长(访问次数过多)。对此的优化正在进行中。不幸的是,我不能使用 EhCache BigMemory(堆外内存),因为它不是免费的(我不是对此做出选择的人)。总结一下:考虑到缓存在 JVM 中,我想调整我的 JVM 配置(暂时不更改应用程序的架构)。
    • 访问内存映射文件中的记录可能需要 50 - 200 纳秒。 (如果它在 OS 磁盘缓存内存中)这不如访问对象中的字段快,但非常快。我不使用 Ehcache,我只使用内存映射文件。
    • 是的,但是我们使用网络文件系统,所以性能不一样。例如,我们正在考虑 Memcached,但它正在进行中,所以我尝试优化实际配置。
    • 确实,网络磁盘的性能不如本地磁盘好。假设您启动本地磁盘,您可以使用直接内存。
    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多