JVM在进行垃圾回收时抛出OutOfMemory错误,尽管还有大量可用内存。

6

我将我的Java应用程序配置为使用5G内存。突然出现了OutOfMemory错误。我检查了GC日志,发现还有很多空闲内存:年轻代占用了分配空间的4%,老年代占用率为5%,永久代占用率为43%。我很困惑为什么JVM在gc时会抛出OutOfMemory错误。有人知道这是为什么吗?非常感谢您的帮助。

JVM内存和gc设置:

-server -Xms5g -Xmx5g -Xss256k -XX:NewSize=2g -XX:MaxNewSize=2g -XX:+UseParallelOldGC -XX:+UseTLAB -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:+DisableExplicitGC

gc.log

2009年09月19日03:34:59.741+0000:92836.778:[GC
期望生存空间大小为152567808字节,新的阈值为1(最大15)
[PSYoungGen:1941492K->144057K(1947072K)] 3138022K->1340830K(5092800K),0.1947640秒] [时间:用户=0.61系统=0.01,真实=0.19秒]
2009年09月19日03:35:29.918+0000:92866.954:[GC
期望生存空间大小为152109056字节,新的阈值为1(最大15)
[PSYoungGen:1941625K->144049K(1948608K)] 3138398K->1341080K(5094336K),0.1942000秒] [时间:用户=0.61系统=0.01,真实=0.20秒]
2009年09月19日03:35:56.883+0000:92893.920:[GC
期望生存空间大小为156565504字节,新的阈值为1(最大15)
[PSYoungGen:1567994K->115427K(1915072K)] 2765026K->1312820K(5060800K),0.1586320秒] [时间:用户=0.50系统=0.01,真实=0.16秒]
2009年09月19日03:35:57.042+0000:92894.079:[GC
期望生存空间大小为179961856字节,新的阈值为1(最大15)
[PSYoungGen:115427K->0K(1898560K)] 1312820K->1313987K(5044288K),0.0775650秒] [时间:用户=0.42系统=0.19,真实=0.08秒]
2009年09月19日03:35:57.120+0000:92894.157:[Full GC [PSYoungGen:0K->0K(1898560K)] [ParOldGen:1313987K->159522K(3145728K)] 1313987K->159522K(5044288K)[PSPermGen:20025K->19942K(40256K)],0.5692300秒][时间:用户=2.18系统=0.05,真实=0.57秒]
2009年09月19日03:35:57.690+0000:92894.726:[GC
期望生存空间大小为197066752字节,新的阈值为1(最大15)
[PSYoungGen:0K->0K(1745728K)] 159522K->159522K(4891456K),0.0072590秒] [时间:用户=0.01系统=0.00,真实=0.00秒]
2009年09月19日03:35:57.698+0000:92894.734:[Full GC [PSYoungGen:0K->0K(1745728K)] [ParOldGen:159522K->158627K(3145728K)] 159522K->158627K(4891456K)[PSPermGen:19942K->19934K(45504K)],0.3280480秒][时间:用户=1.46系统=0.00,真实=0.33秒]
堆
 PSYoungGen    总共1745728K,已用87233K [0x00002aab73650000,0x00002aabf3650000,0x00002aabf3650000)
  eden空间1745664K,已使用4%[0x00002aab73650000,0x00002aab78b80778,0x00002aabddf10000)
  from空间64K,已使用0%[0x00002aabddf10000,0x00002aabddf10000,0x00002aabddf20000)
  to空间192448K,已使用0%[0x00002aabe7a60000,0x00002aabe7a60000,0x00002


我使用的是64位Linux系统和JRE 1.6.0_10版本:

$uname -a
Linux x 2.6.24-etchnhalf.1-amd64 #1 SMP Tue Oct 14 03:11:45 UTC 2008 x86_64 GNU/Linux 

$java -version
java version "1.6.0_10" 
Java(TM) SE Runtime Environment (build 1.6.0_10-b33) 
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)

1
你使用的是哪个JVM?可能它必须是一个64位的JVM吧? - djna
异常的堆栈跟踪是什么? - Martin v. Löwis
1
请编辑完整的堆栈跟踪。OutOfMemory异常用于多种目的,不一定都与堆内存有关。我敢打赌你正在遇到线程创建的问题。 - kdgregory
@Shu L.:作为以后参考,请通过编辑您的问题提供新信息。这种东西在评论中不太容易沟通。 - Stu Thompson
有一位用户在stackoverflow上讨论了一个问题,他提到我们不能将最大堆大小完全设置为物理内存的总大小,最好只设置其50%。这意味着,如果我们拥有5GB的内存,那么我们只能将最大堆大小设置为2.5GB。我找不到那个stackoverflow的帖子。 - ecle
显示剩余5条评论
3个回答

3

好的,也许这个回答有点愚蠢,但是您的计算机确实至少有5GB的RAM,对吗?只是确认一下。 :-) 我不记得JVM是否会检查您是否有足够的内存,直到它尝试分配内存。


0
你可能需要考虑使用分析器和调试器来了解内存溢出错误发生的确切状态。
我使用Jprofiler进行分析,使用Eclipse的调试器进行调试。两者都具有其目的所需的足够功能。
我也希望能看到错误的堆栈跟踪,以确定错误类型和开始出现的位置。这是问题中缺少的非常重要的信息。

0
另外,关于OutOfMemoryException的细节是什么 - 它是否与GC超限有关?如果是这样,那么可以禁用该异常(-XX:-UseGCOverheadLimit)。
请参阅此页面gc选项及其说明

我已经尝试过了,但是没有起作用。我猜根本原因可能是其他的问题。 - Shu L.

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