适当的JVM/GC调优针对具有3GB缓存的4GB JVM

7
我正在寻找适合配置 web应用的JVM设置。我已经了解了老年代/年轻代/永久代,但我在最佳配置中使用这些参数时遇到了麻烦。
在4 GB内,约有 3 GB用于缓存(使用EhCache的应用程序缓存),因此我正在考虑这种情况下的最佳设置。FYI,缓存在应用程序的生命周期内是静态的(从磁盘加载,永不过期),但被大量使用。 我已经对我的应用程序进行了分析,并针对数据库查询、应用程序架构、缓存大小等进行了优化...我只是在寻求JVM配置建议。我已经测量出垃圾收集器的99%吞吐量,以及全面GC运行时的6-8秒暂停(每半个小时左右一次)。
以下是当前的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个内核。

3个回答

6
-XX:+UseParallel*Old*GC可以加速多核机器上的Full GC。
您还可以使用不同的NewRatio值进行分析。缓存的对象将存储在老年代中,因此请使用-XX:NewRatio=7进行分析,然后再尝试一些更高或更低的值。
在分析期间可能无法准确地复制实际使用情况,因此请确保在实际使用时监视GC,然后可以进行微小的更改(例如survivor space等),并查看它们的影响。
旧版建议不要在Xms和Xmx中使用AggressiveHeap,我不确定现在是否仍然适用。 编辑:请告诉我们您部署在哪个操作系统/硬件平台上。
每30分钟进行一次完全收集表明老年代已经相当满了。较高的newRatio值会以年轻代为代价给它更多的空间。您能否为JVM提供超过4g的内存,还是受到限制?
了解您的目标/非功能性需求也将非常有用。您想避免这些6/7秒的暂停而冒降低吞吐量的风险,还是这些暂停是为了最高可能的吞吐量而做出的可接受妥协?
如果您想最小化暂停时间,请尝试使用CMS收集器,方法是删除两个选项。
-XX:+UseParallelGC -XX:+UseParallelOldGC 

并添加

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC

使用各种NewRatio值创建配置文件并查看效果。CMS垃圾回收器的一个缺点是,与并行老年代和串行回收器不同,它不会压缩老年代。如果老年代过于碎片化,并且需要将许多对象一次性提升到老年代进行小型回收,则可能会调用完整的串行回收,这可能会导致长时间的暂停。(我在生产环境中曾经见过这种情况,但使用IBM JVM时会出现内存不足而不是调用压缩回收!)这可能对您来说不是问题-这取决于应用程序的性质-但您可以通过每夜或每周重新启动来避免此问题。

只是为了明确起见,UseParallelOldGC与UseParallelGC不同。如果您使用UseParallelOldGC,则也会打开UseParallelGC,因此您不需要两者都使用。 - Paul Medcraft
我会尽快尝试使用 UseParallelOldGC 和 NewRatio,谢谢。如果有人了解 AggressiveHeap 与 Xms 和 Xmx,请告诉我。 - Matthieu Napoli
UseParallelOldGC并不是很有效果,我得到了40秒的Full GC而不是7秒:D。非常奇怪(我按照你的建议删除了UseParallelGC)。 - Matthieu Napoli
是的,我已经删除了AggressiveHeap并将Xms设置为4096m。我通过GCViewer看到了gc.log,启动速度有所改善(无全局垃圾回收)。 - Matthieu Napoli
机器上是否还有其他繁重的进程在运行?如果是这样,您可能需要告诉它有多少个核心可用于Java:-XX:ParallelGCThreads=2。默认情况下,它将尝试在4核机器上使用全部核心。这是在什么操作系统和硬件上运行的? - Paul Medcraft
显示剩余2条评论

4
我建议使用Java 6更新30或7更新2,64位版本,因为它们更加高效。例如,默认情况下它们使用32位引用。
如果可能的话,我还建议配置Ehcache使用直接内存或内存映射文件。这样可以最大程度地减少对GC的影响。
使用这些选项,几乎可以消除堆占用的痕迹。例如,我的一个应用程序在具有16 GB内存的机器上使用高达180 GB的内存映射文件,而堆大小仅为6 MB。手动触发时,完整的GC需要多达11毫秒,但实际上很少进行GC。
如果您想要一个简单的示例,其中我将8 TB文件映射到内存中并进行更新,请参阅http://vanillajava.blogspot.com/2011/12/using-memory-mapped-file-for-huge.html

升级到Java 6是一个好主意,但这是一项重大的变更,不幸的是这不是我的决定 :( (公司政策) - Matthieu Napoli
关于配置EhCache,已经进行了测试,但由于应用程序的架构,缓存必须在内存中(而不是磁盘上),否则访问时间太长(访问次数太多)。针对此问题的优化正在进行中。不幸的是,我不能使用EhCache BigMemory(非堆内存),因为它不是免费的(我不是做出这个选择的人)。总之:我想调整我的JVM配置,考虑到缓存在JVM中(目前不改变应用程序的架构)。 - Matthieu Napoli
访问内存映射文件中的记录可能需要50-200纳秒(如果它在操作系统磁盘缓存内存中)。这不如访问对象中的字段快,但相当迅速。我不使用Ehcache,我只使用内存映射文件。 - Peter Lawrey
是的,但我们使用网络文件系统,因此性能不同。我们正在考虑使用Memcached,但这还在进行中,所以我尝试优化当前的配置。 - Matthieu Napoli
网络磁盘性能不如本地磁盘,这是事实。如果您使用本地磁盘启动,则可以使用直接内存。 - Peter Lawrey

0

我希望你只是为了不让帖子膨胀而删除了-server,否则你应该立即启用它。除了稍长的启动时间(对于应该运行数天的Web应用程序来说真的不是问题),我没有看到使用c2以外的任何理由。这可能会在一般情况下提供一些良好的性能改进。回到主题:

可悲的是,我所能想到的最好的东西无法与您古老的JVM配合使用。 G1垃圾收集器基本上是为了减少延迟而设计的。它不仅试图减少一般暂停,还提供了一些调整参数来设置暂停目标和间隔。请参见this page

虽然有一个实验性的Java6后移版,但我怀疑它是否被更新。我担心没有人再浪费时间优化GC或其他任何Java 1.5的东西。

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


2
除非它在Windows上运行,否则JVM不会在具有> 2GB RAM的4核机器上默认为服务器模式吗? - Paul Medcraft
@Paul 我不知道有任何这样的优化,但我并不是对Hotspot了解的所有内容都清楚。即使如此,我也不会在条件默认值上冒险使用如此重要的标志。 - Voo
@Paul 有趣的小细节,谢谢。现在 c1 基本上完全没有被使用了(因为热点编译器默认为每个 64 位 CPU 使用 c2)- 这是一个很好的改变。 - Voo
@PaulMedcraft 关于信息,是的,JVM会自动检测当前计算机的“服务器类别”,并相应地更改JVM选项。这被称为“人体工程学设置”http://java.sun.com/performance/reference/whitepapers/tuning.html#section4.1.1,因此无需使用-server。 - Offirmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接