【问题标题】:Error java.lang.OutOfMemoryError: GC overhead limit exceeded错误 java.lang.OutOfMemoryError:超出 GC 开销限制
【发布时间】:2010-11-26 11:33:06
【问题描述】:

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

java.lang.OutOfMemoryError: GC overhead limit exceeded

我知道OutOfMemoryError 是什么,但 GC 开销限制是什么意思?我该如何解决这个问题?

【问题讨论】:

  • 这听起来很有趣。如果有人可以发布一些生成此代码的代码,我会很高兴。
  • 我只是发现了问题,导致内存使用过多,接近堆的限制。一个简单的解决方案可能是简单地为 Java 引擎 (-Xmx) 提供更多堆内存,但这仅在应用程序需要与之前设置的堆限制一样多的内存时才有帮助。
  • @SimonKuang 请注意,有多个OutOfMemoryError 场景增加堆不是一个有效的解决方案:用完本机线程和用完 perm gen(与堆分开)是两个例子。小心不要对OutOfMemoryErrors 做出过于宽泛的陈述;可能导致它们的原因有很多出乎意料的多样性。
  • 你是怎么解决这个问题的??
  • 使用 Jdk1.8.0_91 时发生了这个错误,并且仍然发生在我身上

标签: java garbage-collection out-of-memory heap-memory


【解决方案1】:

此消息表示由于某种原因垃圾收集器占用了过多的时间(默认为进程所有 CPU 时间的 98%)并且每次运行时回收的内存非常少(默认为堆的 2%) .

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

为防止您的应用程序在没有完成任何操作的情况下占用 CPU 时间,JVM 会抛出此 Error,以便您有机会诊断问题。

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

查看 Java GC 调整指南,该指南适用于各种 Java 版本,并包含有关此特定问题的部分:

【讨论】:

  • 将您的答案总结如下是否正确:“这就像'Java 堆空间不足'错误。使用 -Xmx 为其提供更多内存。” ?
  • @Tim:不,那是不正确的。虽然给它更多的内存可以减少问题,但您还应该查看您的代码并了解它为什么会产生这么多垃圾以及为什么您的代码略低于“内存不足”标记。这通常是代码损坏的迹象。
  • 谢谢,看来Oracle在数据迁移方面实际上并没有那么好,他们断开了链接。
  • @Guus:如果多个应用程序在同一个 JVM 中运行,那么是的,它们很容易相互影响。很难判断哪一个行为不端。将应用程序分成不同的 JVM 可能是最简单的解决方案。
  • 我刚刚在使用 Java 7 和一个包含 2001670 行 Java 代码的 Web 应用程序时遇到了这种情况,其中我写了大约 5 行。“你也应该看看你的代码”并非如此在这种情况下很容易。
【解决方案2】:

引用Oracle的文章"Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning"

GC 时间过长和 OutOfMemoryError

如果在垃圾收集上花费了太多时间,并行收集器将抛出 OutOfMemoryError:如果超过 98% 的总时间用于垃圾收集并且回收的堆少于 2%,则会出现 OutOfMemoryError抛出。此功能旨在防止应用程序长时间运行,而由于堆太小而几乎没有进展。如有必要,可以通过在命令行中添加选项 -XX:-UseGCOverheadLimit 来禁用此功能。

编辑:看起来有人打字比我快:)

【讨论】:

  • “你可以把它关掉……”但是 OP 很可能不应该这样做。
  • 你能告诉我“-XX”和“-Xmx”的区别吗?我也可以使用“-Xmx”选项将其关闭。
  • 在这里回复一个非常古老的评论,但是...... @Bart 在几个命令行选项开头的-XX: 是一个标志,表明这个选项是高度特定于VM且不稳定的(在未来的版本中可能会更改,恕不另行通知)。在任何情况下,-XX:-UseGCOverheadLimit 标志告诉 VM 禁用 GC 开销限制检查(实际上是“将其关闭”),而您的 -Xmx 命令只是增加了堆。在后一种情况下,GC 开销检查仍在运行,听起来更大的堆解决了在您的情况下的 GC 抖动问题(这并不总是有帮助)。
  • 在我的应用程序中(在 Talend 中读取一个大型 Excel 文件)这不起作用,从其他用户的解释中我明白了原因。这只是禁用了错误,但问题仍然存在,您的应用程序将花费大部分时间处理 GC。我们的服务器有足够的内存,所以我使用了 Vitalii 的建议来增加堆大小。
  • 如果您的应用程序是数据密集型应用程序,您最终会收到此错误,清除内存并避免数据泄漏是最好的出路 - 但需要一些时间。
【解决方案3】:

如果您确定您的程序中没有memory leaks,请尝试:

  1. 增加堆大小,例如-Xmx1g
  2. 启用并发低暂停收集器-XX:+UseConcMarkSweepGC
  3. 尽可能重用现有对象以节省一些内存。

如有必要,可以通过在命令行中添加选项-XX:-UseGCOverheadLimit 来禁用limit check

【讨论】:

  • 我不同意第三个建议。重用现有对象不节省内存(不要泄漏旧对象节省内存:-) 此外,“重用现有对象”是一种缓解 GC 压力的做法。但这并不总是一个好主意:使用现代 GC,我们应该避免旧对象持有新对象的情况,因为它可能会破坏一些局部性假设......
  • @mcoolive:对于一个有点做作的例子,请参阅下面的 cmets 回答 stackoverflow.com/a/5640498/4178262;在循环内创建 List 对象导致 GC 被调用 39 次而不是 22 次。
【解决方案4】:

通常是代码。这是一个简单的例子:

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");
    }
}

在 Windows 7 32 位上使用 Java 1.6.0_24-b07。

java -Xloggc:gc.log GarbageCollector

那就看gc.log

  • 使用 BAD 方法触发 444 次
  • 使用 WORSE 方法触发 666 次
  • 使用 BETTER 方法触发 354 次

现在承认,这不是最好的测试或最好的设计,但是当你面临除了实现这样一个循环别无选择的情况,或者在处理行为不佳的现有代码时,选择重用对象而不是创建新的可以减少垃圾收集器挡路的次数...

【讨论】:

  • 请澄清:当您说“触发n次”时,是指常规GC发生了n次,还是OP报告的“GC开销限制超出”错误发生了n次?
  • 我刚刚使用 java 1.8.0_91 进行了测试,从未出现错误/异常,并且“触发 n 次”来自于对 gc.log 文件中的行数进行计数。我的测试显示整体次数少得多,但 BETTER 的“触发”次数最少,而现在,BAD 现在比 WORST 更“糟糕”。我的计数:差:26,更差:22,更好 21。
  • 我刚刚添加了一个“WORST_YET”修改,我在 outer loop 而不是 before 外部循环中定义了List&lt;Double&gt; list,并触发了39 次垃圾回收。
【解决方案5】:

根据Java [8] Platform, Standard Edition Troubleshooting Guide的错误原因:(添加了强调和换行)

[...] “GC 开销限制超出”表示垃圾收集器一直在运行,Java 程序进展缓慢。

垃圾回收后,如果 Java 进程花费大约 98% 以上的时间进行垃圾回收,并且它回收的堆空间不足 2% 并且到目前为止一直在这样做最后 5 次(编译时间常数)连续垃圾回收,然后抛出 java.lang.OutOfMemoryError。 [...]

  1. 如果当前堆不够用,则增加堆大小
  2. 如果您在增加堆内存后仍然收到此错误,请使用内存分析工具,例如MAT(内存分析器工具)、Visual VM 等并修复内存泄漏。
  3. 将 JDK 版本升级到最新版本 (1.8.x) 或至少 1.7.x 并使用 G1GC 算法。 . G1 GC 的吞吐量目标是 90% 的应用时间和 10% 的垃圾收集时间
  4. 除了用 -Xms1g -Xmx2g 设置堆内存,试试

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

查看更多有关 G1GC 的相关问题

【讨论】:

    【解决方案6】:

    通过设置这个选项来稍微增加堆大小

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

    -Xms1024M -Xmx2048M
    

    Xms - 最低限制

    Xmx - 最大限制

    【讨论】:

    • Android 应用没有arguments 标签...我们应该怎么做才能做到这一点?
    • 该答案适用于什么工具?这不是 Eclipse 问题。
    • 没有“最低限度”。 -Xms 是初始大小。
    • 可以设置的最大限制是多少??
    • @JPerk 最大值与您机器的物理内存一样多。但是,如果您尝试这样做,其他应用程序将竞争内存使用。
    【解决方案7】:

    试试这个

    打开build.gradle 文件

      android {
            dexOptions {
               javaMaxHeapSize = "4g"
            }
       }
    

    【讨论】:

    • 非常适合模拟器。知道这如何影响真实设备吗?即这是一个好主意还是只是掩盖了问题?谢谢。
    【解决方案8】:

    对我来说,以下步骤有效:

    1. 打开eclipse.ini文件
    2. 改变

      -Xms40m
      -Xmx512m
      

      -Xms512m
      -Xmx1024m
      
    3. 重启 Eclipse

    See here

    【讨论】:

    • 解决此问题的最简单方法。谢谢:)
    • jdev 中的eclipse.ini 文件?
    • 即使将配置更改为此,问题仍未解决。
    • OP 没有问 Eclipse 问题。
    • 这个“答案”没有回答上面的问题。
    【解决方案9】:

    以下内容对我有用。只需添加以下sn-p:

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

    【讨论】:

    • 是的,使用 Gradle 时 :)
    • 你怎么能认为这是他一般问题的解决方案?您将堆大小设置为 4g,这在 Android facepalm 的 gradle 配置中是完全任意的。
    【解决方案10】:

    在 build.gradle(Module:app) 文件中增加 javaMaxHeapsize

    dexOptions {
        javaMaxHeapSize "1g"
    }
    

    到(在gradle中添加这一行)

     dexOptions {
            javaMaxHeapSize "4g"
        }
    

    【讨论】:

      【解决方案11】:

      已解决:
      只需添加
      org.gradle.jvmargs=-Xmx1024m

      gradle.properties
      如果它不存在,则创建它。

      【讨论】:

        【解决方案12】:

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

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

        不一定非得是2048M和32g,随心所欲。

        【讨论】:

          【解决方案13】:

          Java 堆大小说明(xms、xmx、xmn)

          -Xms size in bytes
          
          Example : java -Xms32m
          

          设置 Java 堆的初始大小。 默认大小为 2097152 (2MB)。 这些值必须是 1024 字节 (1KB) 的倍数且大于 1024 字节 (1KB)。 (-server 标志将默认大小增加到 32M。)

          -Xmn size in bytes
          
          Example : java -Xmx2m
          

          设置 Eden 生成的初始 Java 堆大小。 默认值为 640K。 (-server 标志将默认大小增加到 2M。)

          -Xmx size in bytes
          
          Example : java -Xmx2048m
          

          设置 Java 堆可以增长到的最大大小。 默认大小为 64M。 (-server 标志将默认大小增加到 128M。) 最大堆限制约为 2 GB (2048MB)。

          Java 内存参数(xms、xmx、xmn)格式

          在设置 Java 堆大小时,您应该使用字母“m”或“M”中的一个来指定内存参数,或者使用“g”或“G”来表示 GB。如果您指定“MB”或“GB”,您的设置将不起作用。有效参数如下所示:

          -Xms64m 或 -Xms64M -Xmx1g 或 -Xmx1G 也可以用2048MB指定2GB 此外,请确保在指定参数时只使用整数。使用 -Xmx512m 是一个有效的选项,但 -Xmx0.5g 会导致错误。

          此参考可能对某人有所帮助。

          【讨论】:

            【解决方案14】:

            我在 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”文件从: //...

            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
                }
            }
            
            //...
            

                //...
            
            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
                }
            }
            
            //...
            

            【讨论】:

              【解决方案15】:

              要在 IntelliJ IDEA 中增加堆大小,请按照以下说明进行操作。它对我有用。

              对于 Windows 用户,

              进入IDE安装位置,搜索如下。

              idea64.exe.vmoptions
              

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

              -Xms512m
              -Xmx2024m
              -XX:MaxPermSize=700m
              -XX:ReservedCodeCacheSize=480m
              

              就是这样!!

              【讨论】:

                【解决方案16】:

                您可以尝试通过参考此图像对服务器设置进行更改并增加内存大小以进行处理 流程更改以黄色突出显示

                您也可以通过打开 cmd-> set _java_opts -Xmx2g 来更改 Java 堆
                2g(2GB)取决于您的程序的复杂性

                尽量少用常量变量和临时变量

                【讨论】:

                  【解决方案17】:

                  您需要在 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**
                  )
                  

                  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**
                  

                  【讨论】:

                  • 这些设置仅特定于您的本地 IDE。这不适用于 Prod 环境。
                  【解决方案18】:

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

                  【讨论】:

                    【解决方案19】:

                    我不知道这是否仍然相关,但只想分享对我有用的东西。

                    将 kotlin 版本更新到可用的最新版本。 https://blog.jetbrains.com/kotlin/category/releases/

                    它已经完成了。

                    【讨论】:

                      【解决方案20】:

                      @Buhb 我在它的主要方法中的一个普通的spring-boot Web应用程序中复制了这个。代码如下:

                      public static void main(String[] args) {
                          SpringApplication.run(DemoServiceBApplication.class, args);
                          LOGGER.info("hello.");
                          int len = 0, oldlen=0;
                          Object[] a = new Object[0];
                          try {
                              for (; ; ) {
                                  ++len;
                                  Object[] temp = new Object[oldlen = len];
                                  temp[0] = a;
                                  a = temp;
                              }
                          } catch (Throwable e) {
                              LOGGER.info("error: {}", e.toString());
                          }
                      }
                      

                      引起来的示例代码也来自oracle java8语言规范。

                      【讨论】:

                        【解决方案21】:

                        我在使用 Oracle Web 逻辑服务器时遇到了这个错误。我正在分享我的答案以供参考,以防有人最终在这里寻找解决方案。

                        因此,如果您尝试启动 Oracle Web 逻辑服务器并遇到此错误,那么您只需增加为运行服务器设置的初始堆大小和最大堆大小。

                        转到-> C:\Oracle\Middleware\Oracle_Home\user_projects\domains\wl_server\bin

                        打开 setDomainEnv.cmd

                        检查设置 USER_MEM_ARGS 值,如果小于则

                        设置 USER_MEM_ARGS="-Xms128m – Xmx8192m ${MEM_DEV_ARGS} ${MEM_MAX_PERM_SIZE}"

                        这意味着您的初始堆大小设置为 128 MB,最大堆大小为 8GB。 现在,只需保存文件并重新启动服务器。如果不能解决问题,请尝试增加大小或寻找优化服务的方法。

                        对于参考,请查看此链接:https://docs.oracle.com/cd/E49933_01/server.770/es_install/src/tins_postinstall_jvm_heap.html

                        edit:检查您在运行服务器时是否能够看到更新的 java args。就像这样 如果它和以前一样,则通过简单的搜索和替换来替换 setDoaminEnv.cmd 中显示的值。

                        【讨论】:

                          【解决方案22】:

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

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2021-01-07
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2017-12-27
                            • 2020-09-08
                            相关资源
                            最近更新 更多