Fehler java.lang.OutOfMemoryError: GC-Overhead-Limit überschritten

804

Ich erhalte diese Fehlermeldung, wenn ich meine JUnit-Tests ausführe:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Ich weiß, was ein OutOfMemoryErrorist, aber was bedeutet GC-Overhead-Limit? Wie kann ich das lösen?

Mnementh
quelle
16
Das klingt sehr interessant. Ich würde mich freuen, wenn jemand einen Code posten könnte, der dies generiert.
Buhb
1
Ich habe einfach das Problem gefunden, das zu einer zu hohen Speichernutzung nahe der Grenze des Heaps führte. Eine einfache Lösung könnte einfach darin bestehen, der Java-Engine (-Xmx) etwas mehr Heap-Speicher zu geben. Dies hilft jedoch nur, wenn die Anwendung genau so viel Speicher benötigt, wie das zuvor festgelegte Heap-Limit festgelegt wurde.
Mnementh
1
@Mnementh Ich hatte hier eine Antwort gegeben. Überprüfen Sie, ob es hilft. Stackoverflow.com/questions/11091516/…
Lulu
16
@SimonKuang Beachten Sie, dass es mehrere OutOfMemoryErrorSzenarien gibt, für die das Erhöhen des Heapspeichers keine gültige Lösung ist: Es gibt zwei Beispiele dafür, dass keine nativen Threads mehr vorhanden sind und keine Perm-Gene mehr vorhanden sind (die vom Heap getrennt sind). Seien Sie vorsichtig, wenn Sie zu breite Aussagen über machen OutOfMemoryErrors; Es gibt eine unerwartet vielfältige Reihe von Dingen, die sie verursachen können.
Tim
3
Wie haben Sie das Problem gelöst?
Thorsten Niehues

Antworten:

763

Diese Meldung bedeutet, dass der Garbage Collector aus irgendeinem Grund übermäßig viel Zeit in Anspruch nimmt (standardmäßig 98% der gesamten CPU-Zeit des Prozesses) und bei jedem Lauf nur sehr wenig Speicher wiederherstellt (standardmäßig 2% des Heapspeichers).

Dies bedeutet effektiv, dass Ihr Programm keine Fortschritte mehr macht und immer nur die Garbage Collection ausführt.

Um zu verhindern, dass Ihre Anwendung die CPU-Zeit aufnimmt, ohne dass etwas erledigt wird, löst die JVM dies aus, Errordamit Sie die Möglichkeit haben, das Problem zu diagnostizieren.

Die seltenen Fälle, in denen ich dies gesehen habe, sind Fälle, in denen Code Tonnen von temporären Objekten und Tonnen von Objekten mit schwachen Referenzen in einer bereits sehr speicherbeschränkten Umgebung erstellt hat.

Lesen Sie den Java GC-Optimierungsleitfaden, der für verschiedene Java-Versionen verfügbar ist und Abschnitte zu diesem speziellen Problem enthält:

Joachim Sauer
quelle
9
Wäre es richtig, Ihre Antwort wie folgt zusammenzufassen: "Es ist wie ein Fehler 'Out of Java Heap Space'. Geben Sie ihm mit -Xmx mehr Speicher." ?
Tim Cooper
58
@ Tim: Nein, das wäre nicht richtig. Wenn Sie ihm mehr Speicher geben, kann dies das Problem verringern. Sie sollten sich jedoch auch Ihren Code ansehen und herausfinden, warum er so viel Müll produziert und warum Ihr Code knapp unter der Markierung "Nicht genügend Speicher" überfliegt. Es ist oft ein Zeichen für gebrochenen Code.
Joachim Sauer
8
Vielen Dank, es scheint, dass Oracle bei der Datenmigration nicht so gut ist, sie haben die Verbindung unterbrochen.
Joachim Sauer
151
Sie hatten mich bei "Danke, es scheint, dass Oracle nicht wirklich so gut ist"
Rob Grant
3
@Guus: Wenn mehrere Anwendungen in derselben JVM ausgeführt werden, können sie sich leicht gegenseitig beeinflussen. Es wird schwer zu sagen sein, welches sich schlecht benimmt. Die einfachste Lösung besteht darin, die Anwendungen in verschiedene JVMs zu unterteilen.
Joachim Sauer
215

Zitat aus dem Oracle-Artikel "Java SE 6 HotSpot [tm] Optimierung der Garbage Collection für virtuelle Maschinen" :

Übermäßige GC-Zeit und OutOfMemoryError

Der parallele Kollektor löst einen OutOfMemoryError aus, wenn zu viel Zeit für die Speicherbereinigung aufgewendet wird: Wenn mehr als 98% der Gesamtzeit für die Speicherbereinigung aufgewendet werden und weniger als 2% des Heaps wiederhergestellt werden, wird ein OutOfMemoryError ausgelöst. Diese Funktion soll verhindern, dass Anwendungen über einen längeren Zeitraum ausgeführt werden, ohne dass Fortschritte erzielt werden, da der Heap zu klein ist. Bei Bedarf kann diese Funktion deaktiviert werden, indem die Option -XX:-UseGCOverheadLimitzur Befehlszeile hinzugefügt wird.

EDIT: sieht so aus, als könnte jemand schneller tippen als ich :)

Dave
quelle
87
"Sie können dies ausschalten ...", aber das OP sollte dies höchstwahrscheinlich nicht tun.
Stephen C
2
Kannst du mir den Unterschied zwischen "-XX" und "-Xmx" sagen? Ich konnte es auch mit der Option "-Xmx" ausschalten.
Susheel Javadi
19
Auf einen sehr alten Kommentar hier antworten, aber ... @Bart Am -XX:Anfang mehrerer Befehlszeilenoptionen steht eine Art Flag, das angibt, dass diese Option sehr VM-spezifisch und instabil ist (Änderungen vorbehalten in zukünftigen Versionen). In jedem Fall weist das -XX:-UseGCOverheadLimitFlag die VM an, die Überprüfung des GC-Overhead-Limits zu deaktivieren (tatsächlich "ausschaltet"), während Ihr -XmxBefehl lediglich den Heap vergrößert. Im letzteren Fall wurde die GC-Overhead-Überprüfung noch ausgeführt . Es klingt nur so, als hätte ein größerer Haufen die GC-Thrashing-Probleme in Ihrem Fall gelöst (dies hilft nicht immer).
Andrzej Doyle
1
In meiner Anwendung (Lesen einer großen Excel-Datei in Talend) hat dies nicht funktioniert, und anhand der Erklärung anderer Benutzer verstehe ich, warum. Dies deaktiviert nur den Fehler, aber das Problem bleibt bestehen und Ihre Anwendung wird nur die meiste Zeit mit der Bearbeitung von GC verbringen. Unser Server hatte viel RAM, also habe ich die Vorschläge von Vitalii verwendet, um die Heap-Größe zu erhöhen.
RobbZ
Dieser Fehler wird möglicherweise angezeigt, wenn Ihre Anwendung datenintensiv ist. Das Löschen des Speichers und das Umgehen von Datenlecks ist der beste Ausweg - erfordert jedoch einige Zeit.
Pievis
89

Wenn Sie sicher sind, dass Ihr Programm keine Speicherlecks enthält , versuchen Sie Folgendes:

  1. Erhöhen Sie beispielsweise die Heap-Größe -Xmx1g.
  2. Aktivieren Sie den gleichzeitigen Low-Pause-Kollektor -XX:+UseConcMarkSweepGC.
  3. Verwenden Sie vorhandene Objekte nach Möglichkeit erneut, um Speicherplatz zu sparen.

Bei Bedarf kann die Grenzwertprüfung deaktiviert werden, indem die Option -XX:-UseGCOverheadLimitzur Befehlszeile hinzugefügt wird.

Vitalii Fedorenko
quelle
9
Ich bin mit dem dritten Rat nicht einverstanden. Die Wiederverwendung vorhandener Objekte spart keinen Speicher (keine alten Objekte verlieren Speicherplatz :-) Außerdem war "Wiederverwendung vorhandener Objekte" eine Praxis, um den GC-Druck zu verringern. Aber es ist NICHT IMMER eine gute Idee: Mit der modernen GC sollten wir Situationen vermeiden, in denen alte Objekte neue enthalten, da dies einige Lokalitätsannahmen brechen kann ...
mcoolive
@mcoolive: Ein etwas ausgeklügeltes Beispiel finden Sie in den Kommentaren zur Beantwortung von stackoverflow.com/a/5640498/4178262 unten. Durch das Erstellen des ListObjekts innerhalb der Schleife wurde GC 39-mal statt 22-mal aufgerufen.
Mark Stewart
45

Es ist normalerweise der Code. Hier ist ein einfaches Beispiel:

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

Verwenden von Java 1.6.0_24-b07 unter Windows 7 32 Bit.

java -Xloggc:gc.log GarbageCollector

Dann schau mal gc.log

  • 444-mal mit der BAD-Methode ausgelöst
  • 666-mal mit der WORSE-Methode ausgelöst
  • 354-mal mit der BETTER-Methode ausgelöst

Dies ist zwar nicht der beste Test oder das beste Design, aber wenn Sie in einer Situation sind, in der Sie keine andere Wahl haben, als eine solche Schleife zu implementieren, oder wenn Sie mit vorhandenem Code arbeiten, der sich schlecht verhält, kann sich die Entscheidung, Objekte wiederzuverwenden, anstatt neue zu erstellen, verringern wie oft der Müllsammler im Weg ist ...

Mike
quelle
12
Bitte stellen Sie klar: Wenn Sie "n-mal ausgelöst" sagen, bedeutet dies, dass ein regulärer GC n-mal aufgetreten ist oder dass der vom OP gemeldete Fehler "GC-Overhead-Limit überschritten" n-mal aufgetreten ist?
Jon Schneider
Ich habe gerade mit Java 1.8.0_91 getestet und nie einen Fehler / eine Ausnahme erhalten, und das "n-mal ausgelöst" war vom Aufzählen der Anzahl der Zeilen in der gc.logDatei. Meine Tests zeigen insgesamt viel weniger Zeiten, aber die wenigsten "Trigger" -Zeiten für BESSER, und jetzt ist BAD "schlechter" als WORST. Meine Zählungen: SCHLECHT: 26, SCHLECHTER: 22, BESSER 21.
Mark Stewart
Ich habe gerade eine "WORST_YET" -Modifikation hinzugefügt, bei der ich die List<Double> listin der äußeren Schleife anstelle vor der äußeren Schleife definiere und 39 Garbage Collections ausgelöst habe.
Mark Stewart
36

Fehlerursache gemäß Java [8] Platform, Standard Edition - Fehlerbehebungshandbuch : (Hervorhebung und Zeilenumbrüche hinzugefügt)

[...] "GC-Overhead-Limit überschritten" zeigt an, dass der Garbage Collector ständig ausgeführt wird und das Java-Programm nur sehr langsam Fortschritte macht.

Nach einer Speicherbereinigung, wenn der Java-Prozess mehr als ungefähr 98% seiner Zeit mit der Speicherbereinigung verbringt und wenn er weniger als 2% des Heaps wiederherstellt und bisher die letzten 5 (Kompilierungszeitkonstante) aufeinanderfolgenden Speicherbereinigungen durchgeführt hat Sammlungen, dann wird ein java.lang.OutOfMemoryErrorgeworfen. [...]

  1. Erhöhen Sie die Heap-Größe, wenn der aktuelle Heap nicht ausreicht.
  2. Wenn dieser Fehler nach dem Erhöhen des Heap-Speichers immer noch auftritt, verwenden Sie Speicherprofilierungs- Tools wie MAT (Memory Analyzer-Tool), Visual VM usw. und beheben Sie Speicherlecks.
  3. Aktualisieren Sie die JDK-Version auf die neueste Version (1.8.x) oder mindestens 1.7.x und verwenden Sie den G1GC-Algorithmus. . Das Durchsatzziel für den G1 GC liegt bei 90 Prozent Anwendungszeit und 10 Prozent Speicherbereinigungszeit
  4. Xms1g -Xmx2gVersuchen Sie es mit dem Einstellen des Heapspeichers mit -

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

Schauen Sie sich einige weitere verwandte Fragen zu G1GC an

Ravindra Babu
quelle
29

Erhöhen Sie einfach die Heap-Größe ein wenig, indem Sie diese Option aktivieren

Ausführen → Konfigurationen ausführen → Argumente → VM-Argumente

-Xms1024M -Xmx2048M

Xms - für Mindestgrenze

Xmx - für maximale Grenze

hacken
quelle
2
Die Android Apps haben keine argumentsRegisterkarte ... was sollen wir tun, um dies zu erreichen?
Blaze Tama
3
Für welches Tool ist diese Antwort? Das war keine Eclipse-Frage.
Michael Piefel
3
Es gibt keine "Mindestgrenze". -Xms ist die Anfangsgröße.
Diego Queiroz
1
Was ist das Maximum der maximalen Grenze, die eingestellt werden kann?
JPerk
14

Bei mir haben folgende Schritte funktioniert:

  1. Öffnen Sie die eclipse.iniDatei
  2. Veränderung

    -Xms40m
    -Xmx512m

    zu

    -Xms512m
    -Xmx1024m
  3. Starten Sie Eclipse neu

Siehe hier

Sunil Kumar Sahoo
quelle
der einfachste Weg, um dieses Problem zu beheben. Danke :)
Hamza
1
eclipse.ini Datei in jdev?
Abhinaba Basu
Probleme ungelöst, auch wenn die Konfiguration geändert wurde.
Zionpi
1
Das OP hat keine Eclipse-Frage gestellt.
Michael Piefel
1
Diese "Antwort" beantwortet die obige Frage nicht.
Freitags
13

Versuche dies

Öffnen Sie die build.gradleDatei

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }
alicanozkara
quelle
Funktioniert hervorragend für den Simulator. Irgendeine Idee, wie sich dies auf reale Geräte auswirkt? dh ist das eine gute Idee oder maskiert es nur das Problem? Vielen Dank.
Joshua Pinter
11

Folgendes hat bei mir funktioniert. Fügen Sie einfach den folgenden Ausschnitt hinzu:

android {
        compileSdkVersion 25
        buildToolsVersion '25.0.1'

defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 10
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
dexOptions {
        javaMaxHeapSize "4g"
    }
}
Hoshouns
quelle
Ja, wenn Sie Gradle verwenden :)
Alex
4
Wie könnten Sie überhaupt denken, dass dies eine Lösung für seine Frage im Allgemeinen ist ? Sie stellen Ihre Heap-Größe auf 4 g ein, was in einer Gradle-Konfiguration für Android Facepalm völlig willkürlich ist .
Julian L.
7

Erhöhen Sie javaMaxHeapsize in Ihrer build.gradle-Datei (Modul: App)

dexOptions {
    javaMaxHeapSize "1g"
}

zu (Fügen Sie diese Zeile in Gradle hinzu)

 dexOptions {
        javaMaxHeapSize "4g"
    }
Sai Gopi N.
quelle
3

Beschreibungen der Java-Heap-Größe (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Legt die Anfangsgröße des Java-Heaps fest. Die Standardgröße ist 2097152 (2 MB). Die Werte müssen ein Vielfaches von und größer als 1024 Byte (1 KB) sein. (Das Flag -server erhöht die Standardgröße auf 32 MB.)

-Xmn size in bytes

Example : java -Xmx2m

Legt die anfängliche Java-Heap-Größe für die Eden-Generation fest. Der Standardwert ist 640K. (Das Flag -server erhöht die Standardgröße auf 2 MB.)

-Xmx size in bytes

Example : java -Xmx2048m

Legt die maximale Größe fest, bis zu der der Java-Heap wachsen kann. Die Standardgröße ist 64M. (Das Flag -server erhöht die Standardgröße auf 128 MB.) Das maximale Heap-Limit beträgt ca. 2 GB (2048 MB).

Formatierung von Java-Speicherargumenten (xms, xmx, xmn)

Wenn Sie die Größe des Java-Heapspeichers festlegen, sollten Sie Ihr Speicherargument mit einem der Buchstaben "m" oder "M" für MB oder "g" oder "G" für GB angeben. Ihre Einstellung funktioniert nicht, wenn Sie "MB" oder "GB" angeben. Gültige Argumente sehen folgendermaßen aus:

-Xms64m oder -Xms64M -Xmx1g oder -Xmx1G Kann auch 2048 MB verwenden, um 2 GB anzugeben. Stellen Sie außerdem sicher, dass Sie bei der Angabe Ihrer Argumente nur ganze Zahlen verwenden. Die Verwendung von -Xmx512m ist eine gültige Option, aber -Xmx0.5g verursacht einen Fehler.

Diese Referenz kann für jemanden hilfreich sein.

Phönix
quelle
2

Sie können auch die Speicherzuordnung und die Heap-Größe erhöhen, indem Sie dies Ihrer gradle.propertiesDatei hinzufügen :

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

Es muss nicht 2048M und 32g sein, machen Sie es so groß wie Sie wollen.

John Doe
quelle
2

Gelöst:
Fügen Sie einfach
org.gradle.jvmargs=-Xmx1024m
in
gradle.properties
und wenn es nicht vorhanden ist , erstellen Sie es.

reza_khalafi
quelle
0

Ich arbeite in Android Studio und bin auf diesen Fehler gestoßen, als ich versucht habe, ein signiertes APK für die Veröffentlichung zu generieren. Ich konnte ein Debug-APK problemlos erstellen und testen, aber sobald ich ein Release-APK erstellen wollte, lief der Erstellungsprozess minutenlang und endete schließlich mit dem "Fehler java.lang.OutOfMemoryError: GC" Overhead-Limit überschritten ". Ich habe die Heap-Größe sowohl für die VM als auch für den Android DEX-Compiler erhöht, aber das Problem blieb bestehen. Nach vielen Stunden und einer Tasse Kaffee stellte sich schließlich heraus, dass das Problem in meiner 'build.gradle'-Datei auf App-Ebene lag. Ich hatte den Parameter' minifyEnabled 'für den Release-Build-Typ auf' false 'gesetzt und folglich Proguard-Inhalte ausgeführt auf Code, der den Code-Shrinking-Prozess nicht durchlaufen hat (siehe https://developer.android.). Ich habe den Parameter 'minifyEnabled' in 'true' geändert und der Release-Build wie ein Traum ausgeführt :)

Kurz gesagt, ich musste meine 'build.gradle'-Datei auf App-Ebene ändern von: // ...

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

//...

zu

    //...

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

//...
Alex Ivan Howard
quelle
0

Befolgen Sie die folgenden Anweisungen, um die Heap-Größe in IntelliJ IDEA zu erhöhen. Es hat bei mir funktioniert.

Für Windows-Benutzer

Gehen Sie zu dem Speicherort, an dem IDE installiert ist, und suchen Sie nach Folgendem.

idea64.exe.vmoptions

Bearbeiten Sie die Datei und fügen Sie Folgendes hinzu.

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

Das ist es !!

Dulith De Costa
quelle
0

Sie können versuchen, Änderungen an der Servereinstellung vorzunehmen, indem Sie sich auf dieses Bild beziehen und die Speichergröße für gelb hervorgehobene Verarbeitungsprozessänderungen erhöhen

Sie können auch Änderungen am Java-Heap vornehmen, indem set _java_opts -Xmx2g
Sie je nach Komplexität Ihres Programms cmd-> 2g (2gigabyte) öffnen

Versuchen Sie, weniger konstante Variablen und temporäre Variablen zu verwenden

Geben Sie hier die Bildbeschreibung ein

Rahul Jain
quelle
-1

Sie müssen die Speichergröße in Jdeveloper erhöhen . Gehen Sie zu 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**
)

und

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**
Shashi
quelle
4
Diese Einstellungen gelten nur für Ihre lokale IDE. Dies funktioniert nicht für die Prod-Umgebung.
Feng
-1

In Netbeans kann es hilfreich sein, eine maximale Heap-Größe zu entwerfen. Gehen Sie zu Ausführen => Projektkonfiguration festlegen => Anpassen . Im Laufe seiner tauchte Fenster, gehen Sie zu VM Option , füllen Sie bitte -Xms2048m -Xmx2048m. Es könnte das Problem der Heap-Größe lösen.

Xiaogang
quelle
-1

Durch einen Neustart meines MacBook wurde dieses Problem für mich behoben.

Thomas
quelle
-1

Ich weiß nicht, ob dies noch relevant ist oder nicht, sondern möchte nur mitteilen, was für mich funktioniert hat.

Aktualisieren Sie die Kotlin-Version auf die neueste verfügbare Version. https://blog.jetbrains.com/kotlin/category/releases/

und es ist geschafft.

androidStud
quelle