ChatGPT解决这个技术问题 Extra ChatGPT

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

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

java.lang.OutOfMemoryError: GC overhead limit exceeded

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

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

M
Manuel

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

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

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

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

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

Java 11 调优指南有专门针对不同垃圾收集器的过度 GC 部分:对于并发标记清除 (CMS) 收集器的并行收集器,没有提及垃圾优先 (G1) 收集器的这种特定错误情况。

对于并行收集器

用于并发标记扫描 (CMS) 收集器

没有提到垃圾优先 (G1) 收集器的这种特定错误情况。

Java 8 调优指南及其过度 GC 部分

Java 6 调优指南及其过度 GC 部分。


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

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

Excessive GC Time and 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 的建议来增加堆大小。
如果您的应用程序是数据密集型应用程序,您最终会收到此错误,清除内存并避免数据泄漏是最好的解决方法 - 但需要一些时间。
V
Vitalii Fedorenko

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

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

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


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

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

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”修改,我在 外循环 中定义了 List<Double> list 而不是 before 外循环,并触发了 39 次垃圾回收。
S
StackzOfZtuff

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

[...]“超出 GC 开销限制”表示垃圾收集器一直在运行,Java 程序的进度非常缓慢。垃圾回收后,如果 Java 进程花费超过大约 98% 的时间进行垃圾回收,并且如果它回收的堆少于 2%,并且到目前为止一直在做最后 5 个(编译时间常数)连续垃圾集合,然后抛出 java.lang.OutOfMemoryError。 [...]

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

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

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

生产环境中的 Java G1 垃圾收集

用于 GC 微调的 Oracle technetwork 文章


r
randers

只需通过在中设置此选项来稍微增加堆大小

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

-Xms1024M -Xmx2048M

Xms - 最小限制

Xmx - 最大限制


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

尝试这个

打开 build.gradle 文件

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

非常适合模拟器。知道这如何影响真实设备吗?即这是一个好主意还是只是掩盖了问题?谢谢。
H
Hoshouns

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

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 配置中是完全任意的。
M
Mohd Shakir Zakaria

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

打开eclipse.ini文件将-Xms40m -Xmx512m改为-Xms512m -Xmx1024m 重启Eclipse

See here


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

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

dexOptions {
    javaMaxHeapSize "1g"
}

到(在gradle中添加这一行)

 dexOptions {
        javaMaxHeapSize "4g"
    }

r
reza_khalafi

已解决:
只需在
gradle.properties
中添加
org.gradle.jvmargs=-Xmx1024m
,如果不存在,则创建它。


J
John Doe

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

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

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


P
Phoenix

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 会导致错误。

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


D
Du-Lacoste

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

对于 Windows 用户,

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

idea64.exe.vmoptions

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

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

这就对了 !!


A
Alex Ivan Howard

我在 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
    }
}

//...

R
Rahul Jain

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

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

尝试使用较少的常量变量和临时变量

https://i.stack.imgur.com/c6fS0.png


S
Sidharth K.Burnwal

使用 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

https://i.stack.imgur.com/H0Pfc.png


T
Tunaki

您需要在 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 环境。
R
Ravindra babu

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


a
androidStud

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

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

它完成了。


s
spike

@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 语言规范。


T
Thomas

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