错误java.lang.OutOfMemoryError:超出了GC开销限制

Mne*_*nth 766 java garbage-collection heap-memory out-of-memory

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

java.lang.OutOfMemoryError: GC overhead limit exceeded
Run Code Online (Sandbox Code Playgroud)

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

Joa*_*uer 732

此消息表示由于某种原因,垃圾收集器花费了过多的时间(默认情况下为进程的所有CPU时间的98%),并且在每次运行中恢复的内存非常少(默认情况下为堆的2%).

这实际上意味着您的程序停止执行任何进度,并且忙于始终只运行垃圾回收.

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

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

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

  • 你让我在"谢谢,看来甲骨文实际上并不那么好" (142认同)
  • @Tim:不,那不对.虽然给它更多的内存*可以*减少问题,你还应该查看你的代码,看看为什么它产生了大量的垃圾以及为什么你的代码在"内存不足"标记之下掠过.它通常是代码破坏的标志. (56认同)
  • 总结你的答案如下是正确的:"它就像'超出Java堆空间'错误.用-Xmx为它提供更多内存." ? (9认同)
  • 谢谢,似乎Oracle在数据迁移方面实际上并不是那么好,他们打破了链接. (8认同)
  • @Guus:如果多个应用程序在同一个JVM中运行,那么是的,它们很容易相互影响.要说哪一个行为不端是很难的.将应用程序分成不同的JVM可能是最简单的解决方案. (3认同)
  • @TimCooper - 即使对于Out of Java Heap空间错误,老实说也是一个糟糕的答案,尽管有时候肯定是必要的.但是,要触发此错误,您必须打败JVM,它非常善于有效地收集垃圾.如果你看到这个错误,那么你甚至可能会对JVM做一些暴力残忍的事情,而不是你只是在重载堆. (3认同)
  • @TimCooper:只是提供更多内存通常是解决此类问题的直接工具.如果您创建了许多新对象,那么首先查看它是非常有用的,但是如果您正确地分割了内存.通常问题是三个区域中的一个处于上限,但其他区域有足够的自由空间.然后重新分区JVM内存池会有所帮助. (3认同)
  • 我刚刚用Java 7和一个包含2001670行Java代码的Web应用程序发生了这种情况,其中我写了大约5个."你也应该查看你的代码"在这种情况下并不那么容易. (2认同)

dav*_*ave 205

当垃圾收集花费太多时间以获得太少的回报时,GC会抛出此异常,例如.在GC上花费了98%的CPU时间,并且恢复了不到2%的堆.

此功能旨在防止应用程序长时间运行,同时由于堆太小而很少或没有进度.

您可以使用命令行选项将其关闭 -XX:-UseGCOverheadLimit

更多信息在这里

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

  • "你可以把它关掉......"但OP很可能不应该这样做. (84认同)
  • 在这里回复一条非常古老的评论,但是...... @Bart几个命令行选项开头的`-XX:`是一个排序的标志,表明这个选项是高度特定于虚拟机的并且不稳定(如有更改,恕不另行通知在未来的版本中).在任何情况下,`-XX:-UseGCOverheadLimit`标志告诉VM禁用GC开销限制检查(实际上"关闭它"),而你的`-Xmx`命令只增加了堆.在后一种情况下,GC开销检查仍在*运行*,它听起来像一个更大的堆解决了你的情况下的GC颠簸问题*(这并不总是有帮助). (18认同)
  • 你能告诉我"-XX"和"-Xmx"之间的区别吗?我也可以使用"-Xmx"选项将其关闭. (2认同)

Vit*_*nko 85

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

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

如有必要,可以通过在命令行中添加选项来禁用限制检查-XX:-UseGCOverheadLimit.

  • 我不同意第三条建议.重用现有对象不会节省内存(不要泄漏旧对象,节省内存:-)此外,"重用现有对象"是缓解GC压力的一种做法.但它并不总是一个好主意:对于现代GC,我们应该避免旧对象拥有新对象的情况,因为它可能会打破一些地方假设...... (9认同)

Mik*_*ike 44

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

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

使用java 1.6.0_24-b07在Windows7 32位上.

java -Xloggc:gc.log GarbageCollector

然后看看gc.log

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

现在被授予,这不是最好的测试或最好的设计,但是当遇到除了实现这样的循环或者处理行为不好的现有代码时别无选择的情况时,选择重用对象而不是创建新对象可以减少垃圾收集器挡住的次数......

  • 请澄清:当您说"触发n次"时,这是否意味着常规GC发生了n次,或者OP报告的"GC开销限制超出"错误发生了n次? (12认同)

Rav*_*abu 33

导致错误的原因

超出GC开销限制"表示垃圾收集器一直在运行,Java程序进展非常缓慢.

在垃圾收集之后,如果Java进程花费超过大约98%的时间进行垃圾收集,并且它正在恢复少于2%的堆并且到目前为止已经执行了最后5个(编译时常量)连续垃圾集合,然后抛出java.lang.OutOfMemoryError

  1. 如果当前堆不够,请增加堆大小.
  2. 如果您还在不断增加堆内存后出现此错误,使用内存分析工具MAT(内存分析工具), 视觉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
    
    Run Code Online (Sandbox Code Playgroud)

看看有关G1GC的一些更相关的问题

关于G1的Java 7(JDK 7)垃圾收集和文档

生产中的Java G1垃圾收集

用于GC微调的Oracle technetwork文章


cho*_*pss 29

只需在此处设置此选项,即可稍微增加堆大小

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

-Xms1024M -Xmx2048M
Run Code Online (Sandbox Code Playgroud)

Xms - 最低限度

Xmx - 最大限制

  • 这个答案是什么工具?那不是 Eclipse 的问题。 (3认同)
  • 没有"最低限度".-Xms是初始大小. (3认同)
  • Android应用程序没有"参数"选项卡......我们应该怎么做才能实现这一目标? (2认同)

Sun*_*hoo 16

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

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

    -Xms40m
    -Xmx512m
    
    Run Code Online (Sandbox Code Playgroud)

    -Xms512m
    -Xmx1024m
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重启Eclipse

看这里

  • jdev 中的 eclipse.ini 文件? (2认同)
  • OP 没有问 Eclipse 问题。 (2认同)
  • 这个“答案”并没有回答上面的问题。 (2认同)

ali*_*ara 12

试试这个

打开build.gradle文件

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }
Run Code Online (Sandbox Code Playgroud)


小智 12

以下对我有用.只需添加以下代码段:

android {
        compileSdkVersion 25
        buildToolsVersion '25.0.1'

defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 10
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
dexOptions {
        javaMaxHeapSize "4g"
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你怎么能认为这是他的问题的解决方案*一般*?您将堆大小设置为4g,这在Android*facepalm*的gradle配置中完全是任意的. (3认同)

Sai*_*i N 7

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

dexOptions {
    javaMaxHeapSize "1g"
}
Run Code Online (Sandbox Code Playgroud)

到(在gradle中添加此行)

 dexOptions {
        javaMaxHeapSize "4g"
    }
Run Code Online (Sandbox Code Playgroud)


rez*_*afi 7

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

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


Joh*_*Doe 6

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

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

不一定要2048M和32g,想多大就多大。


Pho*_*nix 5

Java 堆大小描述(xms、xmx、xmn)

\n\n
-Xms size in bytes\n\nExample : java -Xms32m\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
-Xmn size in bytes\n\nExample : java -Xmx2m\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
-Xmx size in bytes\n\nExample : java -Xmx2048m\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

设置 Java 堆大小时,应使用字母 \xe2\x80\x9cm\xe2\x80\x9d 或 \xe2\x80\x9cM\xe2\x80\x9d(MB)之一或 \xe2\ 来指定内存参数。 GB 为 x80\x9cg\xe2\x80\x9d 或 \xe2\x80\x9cG\xe2\x80\x9d。如果您指定 \xe2\x80\x9cMB\xe2\x80\x9d 或 \xe2\x80\x9cGB,您的设置将\xe2\x80\x99t 不起作用。\xe2\x80\x9d 有效参数如下所示:

\n\n

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

\n\n

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

\n


归档时间:

查看次数:

854477 次

最近记录:

6 年,2 月 前