JVM Tenured / Old gen达到极限&服务器挂

时间:2011-05-09 15:48:09

标签: java jboss garbage-collection jvm heap-memory

我们的应用程序需要非常大的内存,因为它处理非常大的数据。因此,我们将最大堆大小增加到12GB(-Xmx)。

以下是环境详情

OS - Linux 2.6.18-164.11.1.el5    
JBoss - 5.0.0.GA
VM Version - 16.0-b13 Sun JVM
JDK - 1.6.0_18

我们有以上环境&我们的质量保证和配置中的配置刺。 在QA中,我们将最大PS Old Gen(堆内存)分配为8.67GB,而在Prod中它只有8GB。

在Prod中,对于特定的工作,Old Gen Heap达到8GB,挂起并且Web URL无法访问。服务器正在崩溃。 但在QA中它也达到了8.67GB,但是执行了完整的GC并且它恢复到6.5GB或者其他东西。这里没有被绞死。

我们无法找到解决方案,因为两个方框的环境和配置都是相同的。

我在这里有3个问题,

  

最大堆的2/3将被分配给   老/终年。如果是这样的话   为什么它在一个地方8GB和8.67GB   在另一个地方?

     

如何为New提供有效比率   在这种情况下的使用权(12GB)?

     

为什么它在一个地方完全GCed   不在另一个?

任何帮助都会非常明显。感谢。

如果您需要有关env或conf的详细信息,请告诉我。

2 个答案:

答案 0 :(得分:22)

针对您的具体问题:

  1. 新旧代之间的默认比例取决于系统以及JVM确定的最佳选择。
  2. 使用-XX:NewRatio=3指定新旧代之间的特定比率。
  3. 如果您的JVM挂起并且堆已满,则可能会卡住常量GC。
  4. 听起来你需要更多的内存来生产。如果在QA上请求结束,则可能需要额外的0.67GB。这似乎并没有给你留下太多空间。你在QA上进行的测试与prod上的相同吗?

    由于您使用的是12GB,因此必须使用64位。您可以使用-XX:+UseCompressedOops选项来节省64位寻址的内存开销。它通常可以节省40%的内存,因此你的12GB将会更进一步。

    根据您正在做的事情,并发收集器可能也会更好,特别是减少长GC暂停时间。我建议尝试这些选项,因为我发现它们运行良好:

    -Xmx12g -XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:+UseCompressedOops
    -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC
    -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled
    -XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68
    

答案 1 :(得分:3)

您需要获取更多数据才能知道发生了什么,然后才能知道需要修复的内容。在我看来,这意味着

  1. 获取有关垃圾收集器正在做什么的详细信息,这些参数是一个好的开始(替换一些首选路径和文件代替gc.log)

    -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:gc.log -verbose:gc

  2. 重复运行,扫描gc日志中挂起的时间段&用该输出回复

  3. 考虑使用visualgc观看输出(需要在服务器上运行jstatd,一个随机链接解释如何进行此设置this one),这是jvmstat的一部分,这是av轻松查看堆中各代的大小(尽管可能不是6小时!)

  4. 我也强烈建议你做一些阅读,这样你就知道所有这些开关所指的是什么,否则你会盲目地尝试那些没有真正理解为什么有一件事有帮助而另一件没有帮助的东西。我将从oracle java 6 gc调优页面开始,您可以找到here

    我建议您在基线效果后更改选项。虽然说CompressedOops可能很容易获胜,但您可能需要注意它自6月23日起默认为默认。

    最后你应该考虑升级jvm,6u18稍微增加,性能不断提高。

      

    每项工作需要3个小时才能完成,差不多有6个工作一个接一个地运行。运行时的最后一个作业达到最大8GB并在prod中挂起

    这些工作是否相关?如果他们不在同一个数据集上工作,这听起来像是一个渐进的内存泄漏。如果堆使用率不断上升并最终导致内存泄漏,那么就会出现内存泄漏。你应该考虑使用-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/some/dir来捕获堆转储(尽管注意13G堆它将是一个大文件,所以确保你有磁盘空间)如果/什么时候爆炸。然后,您可以使用jhat来查看当时堆上的内容。