Java.lang.OutOfMemoryError: GC overhead limit exceeded (错误:超过GC开销限制)

323
我在一个创建数百万个HashMap对象的程序中遇到了错误,每个对象包含15-20个文本条目。这些字符串必须全部收集(不分成较小的部分)后才能提交到数据库。根据Sun的说法,如果垃圾回收花费的时间太长,即如果总时间的98%以上用于垃圾回收,且只恢复了不到2%的堆,则会抛出OutOfMemoryError错误。显然,可以使用命令行向JVM传递参数来解决此问题,方法如下:
增加堆大小,通过"-Xmx1024m"(或更多);或者
完全禁用错误检查,通过"-XX:-UseGCOverheadLimit"。
第一种方法可以正常工作,而第二种方法最终会导致另一个java.lang.OutOfMemoryError错误,这次是关于堆的。因此,问题是:对于特定用例(即多个小HashMap对象),是否有编程替代方案?例如,如果我使用HashMap clear() 方法,则问题就解决了,但存储在HashMap中的数据也会消失!:-) 这个问题也在StackOverflow的相关主题中讨论过。

1
您可能需要更改算法并使用一些更有效的数据结构。您能告诉我们您正在尝试实现哪个算法,需要那么多HashMap吗? - Ankur
我正在阅读非常大的文本文件(每个文件有数十万行),我对它们没有控制权,即它们不能被分解。对于每行文本,构建一个包含少量字符串值(实际上约为10个)的HashMap,再次使用相同的数据库字段名称。理想情况下,我希望在将数据发送到数据库之前能够读取整个文件。 - PNS
1
似乎在将数据发送到数据库之前读取整个文件是非常糟糕的解决方案... 实际上,由于可用内存的非常真实的限制,这根本行不通。无论如何你为什么要这样做?"一遍又一遍地使用相同的数据库字段名称"是什么意思?作为键或值的字段名称?如果这些字段是键,则只需使用数组,其中该字段被其位置隐含表示...如果它们是值,则在将它们添加到映射之前将它们内部化。了解数据是什么将有所帮助。祝好。Keith. - corlettk
1
它们是具有恒定值的键。Intern 确实有所帮助,谢谢。 - PNS
16个回答

3

使用像eclipse MATVisualVM这样的性能分析工具来修复您应用程序中的内存泄漏问题。

对于JDK 1.7.x或更高版本,请使用G1GC它将10%的时间用于垃圾回收,而其他GC算法仅使用2%。

除了使用-Xms1g -Xmx2g设置堆内存外,请尝试`

-XX:+UseG1GC 
-XX:G1HeapRegionSize=n, 
-XX:MaxGCPauseMillis=m, 
-XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n`

请查看oracle的文章,以了解如何优化这些参数。
一些与SE中G1GC相关的问题: Java 7 (JDK 7)垃圾回收和G1文档 生产环境中的Java G1垃圾回收 积极的垃圾收集器策略

3

如果您想在应用 gradle 文件的 android 闭包下使用以下代码。

dexOptions { javaMaxHeapSize "4g" }


(此代码可增加 Java 堆大小,以帮助处理更大型的应用程序)

2

如果出现以下错误:

"内部编译器错误: java.lang.OutOfMemoryError: GC overhead limit exceeded at java.lang.AbstractStringBuilder"

将Java堆空间增加到2GB,即 -Xmx2g。


2

您需要在 Jdeveloper 中增加内存大小,请前往 setDomainEnv.cmd 进行设置。

set WLS_HOME=%WL_HOME%\server
set XMS_SUN_64BIT=256
set XMS_SUN_32BIT=256
set XMX_SUN_64BIT=3072
set XMX_SUN_32BIT=3072
set XMS_JROCKIT_64BIT=256
set XMS_JROCKIT_32BIT=256
set XMX_JROCKIT_64BIT=1024
set XMX_JROCKIT_32BIT=1024

if "%JAVA_VENDOR%"=="Sun" (
    set WLS_MEM_ARGS_64BIT=-Xms256m -Xmx512m
    set WLS_MEM_ARGS_32BIT=-Xms256m -Xmx512m
) else (
    set WLS_MEM_ARGS_64BIT=-Xms512m -Xmx512m
    set WLS_MEM_ARGS_32BIT=-Xms512m -Xmx512m
)
and

set MEM_PERM_SIZE_64BIT=-XX:PermSize=256m
set MEM_PERM_SIZE_32BIT=-XX:PermSize=256m

if "%JAVA_USE_64BIT%"=="true" (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT%

) else (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT%
)

set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=1024m
set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=1024m

1
对于我的情况,使用-Xmx选项增加内存是解决方案。
我在Java中读取了一个10GB的文件,每次都会遇到同样的错误。当top命令中RES列中的值达到-Xmx选项设置的值时,就会发生这种情况。然后通过使用-Xmx选项增加内存,一切都变得顺利了。
还有另一点。当我在用户帐户中设置JAVA_OPTSCATALINA_OPTS并再次增加内存时,我遇到了相同的错误。然后,我在我的代码中打印了这些环境变量的值,发现与我设置的不同。原因是Tomcat是该进程的根,而我不是su-doer,所以我请求管理员在Tomcat的catalina.sh中增加内存。

0

这帮助我摆脱了这个错误。此选项禁用-XX:+ DisableExplicitGC


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