关于垃圾收集:错误java.lang.OutOfMemoryError:超出了GC开销限制

Error java.lang.OutOfMemoryError: GC overhead limit exceeded

我在执行JUnit测试时收到此错误消息:

1
java.lang.OutOfMemoryError: GC overhead limit exceeded

我知道什么是GC开销限制,但是GC开销限制意味着什么?我怎么解决这个问题?


此消息意味着由于某种原因,垃圾收集器占用了过多的时间(默认情况下,占进程所有CPU时间的98%)并在每次运行中恢复很少的内存(默认情况下为堆的2%)。

这实际上意味着您的程序停止执行任何进度,并且一直只忙于运行垃圾收集。

为了防止您的应用程序在不做任何事情的情况下占用CPU时间,JVM会抛出这个命令,这样您就有机会诊断该问题。

我见过这种情况的罕见情况是,有些代码在一个已经非常受内存限制的环境中创建了大量的临时对象和大量的弱引用对象。

查看本文了解详细信息(特别是本部分)。


当垃圾收集花费的时间太多而返回的时间太少时,GC会抛出此异常,例如98%的CPU时间花费在GC上,而回收的堆少于2%。

此功能旨在防止应用程序长时间运行,同时由于堆太小而进展甚微或没有进展。

可以使用命令行选项关闭此选项-XX:-UseGCOverheadLimit

此处提供更多信息

编辑:似乎有人键入的速度比我快:)


如果您确定程序中没有内存泄漏,请尝试:

  • 增加堆大小,例如-Xmx1g
  • 启用并发低暂停收集器。
  • 尽可能重用现有对象以保存一些内存。
  • 如有必要,可以通过将选项-XX:-UseGCOverheadLimit添加到命令行来禁用限制检查。


    通常是密码。下面是一个简单的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import java.util.*;

    public class GarbageCollector {

        public static void main(String... args) {

            System.out.printf("Testing...%n");
            List<Double> list = new ArrayList<Double>();
            for (int outer = 0; outer < 10000; outer++) {

                // list = new ArrayList<Double>(10000); // BAD
                // list = new ArrayList<Double>(); // WORSE
                list.clear(); // BETTER

                for (int inner = 0; inner < 10000; inner++) {
                    list.add(Math.random());
                }

                if (outer % 1000 == 0) {
                    System.out.printf("Outer loop at %d%n", outer);
                }

            }
            System.out.printf("Done.%n");
        }
    }

    使用Java1.60Y24-B07在WiNoS7 32位上。

    Java-XLogGC:gc.log GarbageCollector

    然后查看gc.log

    • 用坏方法触发444次
    • 使用更差的方法触发666次
    • 使用更好的方法触发354次

    当然,这不是最佳测试或最佳设计,但是当面临这样一种情况时,你别无选择,只能实现这样一个循环,或者在处理行为不好的现有代码时,选择重用对象而不是创建新的对象可以减少垃圾回收的次数。收藏家妨碍了…


    错误的原因

    GC overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress.

    在垃圾回收之后,如果Java进程花费超过大约98%的时间进行垃圾收集,并且如果它正在回收小于2%的堆,并且到目前为止已经做了最后5个(编译时间常数)连续垃圾收集,则是JavaLang.OutOfMeMeMyReReR。或被抛出

  • 如果当前堆不够,请增大堆大小。
  • 如果在增加堆内存后仍然出现此错误,请使用内存分析工具(如mat(内存分析器工具)、VisualVM等)并修复内存泄漏。
  • 升级jdk版本至最新版本(1.8.x)或至少1.7.x并使用gggc算法。。g1 gc的吞吐量目标是90%的应用程序时间和10%的垃圾收集时间。
  • 除了使用-Xms1g -Xmx2g设置堆内存外,还可以尝试

    1
    2
    -XX:+UseG1GC -XX:G1HeapRegionSize=n -XX:MaxGCPauseMillis=m  
    -XX:ParallelGCThreads=n -XX:ConcGCThreads=n
  • 看一看关于g1gc的一些更相关的问题

    JAVA 7(JDK 7)垃圾收集和G1文档

    JAVA G1垃圾回收在生产中的应用

    用于GC微调的Oracle Technetwork文章


    只需将此选项设置为

    运行→运行配置→参数→VM参数

    1
    -Xms1024M -Xmx2048M

    xms-最小限值

    xmx-最大限值


    对我来说,以下步骤奏效了:

  • 打开文件
  • 更改

    1
    2
    -Xms40m
    -Xmx512m

    1
    2
    -Xms512m
    -Xmx1024m
  • 重新启动Eclipse

  • 请看这里


    以下内容对我很有用。只需添加以下代码段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    android {
            compileSdkVersion 25
            buildToolsVersion '25.0.1'

    defaultConfig {
            applicationId"yourpackage"
            minSdkVersion 10
            targetSdkVersion 25
            versionCode 1
            versionName"1.0"
            multiDexEnabled true
        }
    dexOptions {
            javaMaxHeapSize"4g"
        }
    }


    试试这个

    打开文件

    1
    2
    3
    4
    5
      android {
            dexOptions {
               javaMaxHeapSize ="4g"
            }
       }


    在build.gradle(module:app)文件中增加javamaxheapsize

    1
    2
    3
    dexOptions {
        javaMaxHeapSize"1g"
    }

    到(渐变添加此行)

    1
    2
    3
     dexOptions {
            javaMaxHeapSize"4g"
        }


    重新启动我的MacBook为我解决了这个问题。


    您还可以通过将其添加到gradle.properties文件来增加内存分配和堆大小:

    org.gradle.jvmargs=-Xmx2048M -XX\:MaxHeapSize\=32g

    它不必是2048米和32克,让它像你想要的那样大。


    我在Android Studio中工作,在尝试生成已签名的APK以供发布时遇到此错误。我能够构建和测试一个调试APK,没有问题,但是一旦我想要构建一个发布APK,构建过程将运行几分钟,然后最终以"错误java.lang.outofmemoryerror:gc开销限制超过"终止。我增加了vm和android dex编译器的堆大小,但问题仍然存在。最后,在花了很多小时喝了几杯咖啡后,发现问题出在我的应用程序级"build.gradle"文件中-我将"minifyenabled"参数设置为"false",因此在没有经过代码收缩处理的代码上运行proguard程序(请参见https://developer.android.com/studio/build/shrink code.html)。我将"minifyenabled"参数更改为"true",并像做梦一样执行发布版本:)

    简而言之,我必须将应用程序级别的"build.gradle"文件从以下位置更改为://……

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.sign_config_release
        }
        debug {
            debuggable true
            signingConfig signingConfigs.sign_config_debug
        }
    }

    //...

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
        //...

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.sign_config_release
        }
        debug {
            debuggable true
            signingConfig signingConfigs.sign_config_debug
        }
    }

    //...

    要在Intellij IDEA中增加堆大小,请遵循以下说明。这对我很有用。

    对于Windows用户,

    转到安装IDE的位置并搜索以下内容。

    1
    idea64.exe.vmoptions

    编辑文件并添加以下内容。

    1
    2
    3
    4
    -Xms512m
    -Xmx2024m
    -XX:MaxPermSize=700m
    -XX:ReservedCodeCacheSize=480m

    就是这样!你看!


    我正在使用apache-tomcat-8.5.37。我也面临同样的错误

    java.lang.outofmemoryerror: gc overhead limit exceeded

    我在上面读到一个解决方案说

    Increase the heap size, for example -Xmx1g. Enable the concurrent low
    pause collector -XX:+UseConcMarkSweepGC. Reuse existing objects when
    possible to save some memory. If necessary, the limit check can be
    disabled by adding the option -XX:-UseGCOverheadLimit to the command
    line.

    这个解决方案对某人有效吗?需要关于解决问题的建议。


    您需要在jdeveloper中增加内存大小,请转到setdomainev.cmd。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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**
    )

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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**


    在NetBeans中,设计最大堆大小可能会有所帮助。转到运行=>设置项目配置=>自定义。在弹出窗口的运行中,转到vm选项,填写-Xms2048m -Xmx2048m。它可以解决堆大小问题。