为什么java堆分配调整大小会导致OOME?

为什么java堆分配调整大小会导致OOME?,java,garbage-collection,heap,out-of-memory,heap-dump,Java,Garbage Collection,Heap,Out Of Memory,Heap Dump,为什么java堆分配调整大小会导致OOME 我们在日志中看到OutOfMemoryException,它们似乎与java堆提交大小从~1G增长到~2.4G一致。尽管出现了错误消息,但堆空间似乎没有用完。除了抛出异常(并生成堆转储)之外,调整大小似乎最终会成功,并且应用程序继续运行,不会出现问题(堆提交大小约为2.4G) 以下是日志输出的示例: INFO | jvm 1 | 2013/08/16 12:08:05 | [GC [PSYoungGen: 328000K->2997K(

为什么java堆分配调整大小会导致OOME

我们在日志中看到OutOfMemoryException,它们似乎与java堆提交大小从~1G增长到~2.4G一致。尽管出现了错误消息,但堆空间似乎没有用完。除了抛出异常(并生成堆转储)之外,调整大小似乎最终会成功,并且应用程序继续运行,不会出现问题(堆提交大小约为2.4G)

以下是日志输出的示例:

INFO   | jvm 1    | 2013/08/16 12:08:05 | [GC [PSYoungGen: 328000K->2997K(339200K)] 645686K->320683K(1038272K), 0.0101580 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
INFO   | jvm 1    | 2013/08/16 12:09:14 | [GC [PSYoungGen: 331509K->3487K(338816K)] 649195K->322153K(1037888K), 0.0115600 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:09:59 | [GC [PSYoungGen: 331999K->2928K(340032K)] 650665K->322608K(1039104K), 0.0099300 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:10:48 | [GC [PSYoungGen: 333104K->2723K(339648K)] 652784K->323240K(1038720K), 0.0100130 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:28 | [GC [PSYoungGen: 332885K->3884K(340864K)] 653402K->325089K(1039936K), 0.0106250 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:39 | [GC [PSYoungGen: 23694K->463K(340352K)] 344899K->323656K(2437504K), 0.0070330 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:39 | [GC [PSYoungGen: 463K->0K(340608K)] 323656K->323592K(2437760K), 0.0044440 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:39 | [Full GC
INFO   | jvm 1    | 2013/08/16 12:11:40 |  [PSYoungGen: 0K->0K(340608K)] [PSOldGen: 323592K->323592K(699072K)] 323592K->323592K(1039680K) [PSPermGen: 159297K->159297K(262144K)], 1.2076900 secs] [Times: user=1.20 sys=0.00, real=1.21 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:40 | [GC [PSYoungGen: 0K->0K(340736K)] 323592K->323592K(2437888K), 0.0046330 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:40 | [Full GC
INFO   | jvm 1    | 2013/08/16 12:11:42 |  [PSYoungGen: 0K->0K(340736K)] [PSOldGen: 323592K->279953K(744512K)] 323592K->279953K(1085248K) [PSPermGen: 159297K->159062K(262144K)], 1.7593100 secs] [Times: user=1.75 sys=0.00, real=1.76 secs] 
INFO   | jvm 1    | 2013/08/16 12:11:42 | java.lang.OutOfMemoryError: Java heap space
INFO   | jvm 1    | 2013/08/16 12:11:42 | Dumping heap to java_pid28908.hprof ...
INFO   | jvm 1    | 2013/08/16 12:11:48 | Heap dump file created [463314899 bytes in 6.037 secs]
INFO   | jvm 1    | 2013/08/16 12:12:36 | [GC [PSYoungGen: 331840K->6044K(352192K)] 611793K->285998K(2449344K), 0.0164060 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 
INFO   | jvm 1    | 2013/08/16 12:13:28 | [GC [PSYoungGen: 352156K->6161K(364160K)] 632110K->286114K(2461312K), 0.0152330 secs] [Times: user=0.02 sys=0.01, real=0.01 secs] 
INFO   | jvm 1    | 2013/08/16 12:14:47 | [GC [PSYoungGen: 364113K->6575K(374144K)] 644066K->288169K(2471296K), 0.0179930 secs] [Times: user=0.02 sys=0.01, real=0.02 secs] 
请注意,在OOME之前,提交的堆总量在1GB和2.4GB之间波动。我们可以看到,它在1GB之前相当稳定,在2.4GB之后相当稳定

此1.6.0.\u 24 JVM的Java选项包括:

  • -Xmx3072m
  • -XX:+HEAPDUMPONAUTOFMEMORYERROR
  • -XX:-使用GCOverdeLimit
  • -详细:gc
  • -Xss256k
  • -XX:MaxPermSize=256m
  • -服务器
  • -XX:+PrintGCDetails
JVM正在运行1.6.0。我们现在无法更改版本,但在未来一两个月内将有一个窗口进行更改。如果1.6.0_45更稳定,我们将致力于切换到该版本。我们目前正在测试它

这台机器只有4GB的总系统ram。此外,还有一个小型RAM磁盘也在使用中。我担心Xmx设置对于这个环境来说已经太高了

这让我们感到困惑,因为在发生异常时,堆的使用率似乎不是很大。为什么我们会得到这个OOME


更新:我们试图通过将初始内存(Xms)设置为最大内存(Xmx)来防止这种情况。到目前为止,这些实验是有希望的,尽管我们还没有在生产中引入变化。它仍然没有解释为什么OOME会首先出现,尽管它确实表明在不增加最大堆大小(或减少应用程序内存占用)的情况下可以避免OOME。因此,堆大小调整为什么会导致OOME的谜团依然存在?

对于读取日志而言,似乎您有一个非常大的活动突发,最像是大到足以直接进入终身/旧代的对象。我仍然建议您增加最大内存,以查看应用程序的行为,因为OOME可能会给您带来混乱的统计数据


这意味着提前大量促销。“GC”是一个小集合,似乎每个对象都是必需的,它触发了一个完整的GC,该GC找到一些可以删除的永久对象。当年轻的物体在伊甸园空间死亡时,GC工作得最好,但看起来你的大多数物体都在终身空间死亡

测试这一点的一种方法是使最大堆空间更大。如果您可以尝试24GB堆或80%的主内存,请查看它的行为。e、 g.如果您有32 GB内存,请尝试使用
-Xmx24g
。从这些数字来看,您似乎希望Eden的大小至少为5 GB

如果这不是一个选项,我建议您使用内存分析器将内存消耗至少减少3倍


我会检查您是否有最新版本的Java6,如update 45。更新18和更新26之间有显著的性能改进。

它的可重复性如何?您能告诉我们一些代码中发生这种情况的区域吗?到目前为止,我们无法在测试环境中重现它,尽管我们仍在尝试。在生产过程中每隔几天就会发生一次。据我所知,这似乎是基于堆的总体增长,而不是我们代码中的任何特定部分。既然我已经缩小了问题的焦点,也许您可以重写或添加您的答案?好的,我们将在测试环境中尝试更大的堆大小。我担心这会导致操作系统的死机,因为机箱上只有4GB内存,但我们会尝试。我建议购买更多内存。你可以用低于1000美元的价格买到32GB。这个应用程序运行在嵌入式硬件上,在这个领域有上百个。所以你认为OOME掩盖了实际的峰值内存使用?是的。如果您限制了内存消耗,我建议您对应用程序进行内存配置,以减少其消耗。如果您以前没有这样做过,您应该能够将其使用率降低一半或更好。