Errore java.lang.OutOfMemoryError: limite generale GC superato


805

Ricevo questo messaggio di errore mentre eseguo i test JUnit:

java.lang.OutOfMemoryError: GC overhead limit exceeded

So cosa OutOfMemoryErrorè, ma cosa significa limite generale GC? Come posso risolvere questo?


16
Sembra molto interessante. Mi piacerebbe se qualcuno potesse pubblicare del codice che genera questo.
Buhb,

1
Ho semplicemente trovato il problema, che porta a un uso eccessivo della memoria, vicino al limite dell'heap. Una soluzione semplice potrebbe essere semplicemente quella di fornire un po 'più di memoria Heap al motore Java (-Xmx), ma ciò aiuta solo se l'applicazione ha bisogno esattamente della stessa quantità di memoria del limite di heap precedentemente impostato.
Mnementh,

1
@Mnementh ho dato una risposta qui per verificare se aiuta stackoverflow.com/questions/11091516/…
lulu

16
@SimonKuang Si noti che esistono diversi OutOfMemoryErrorscenari per i quali aumentare l'heap non è una soluzione valida: l'esaurimento dei thread nativi e l'esaurimento di perm gen (che è separato dall'heap) sono due esempi. Fai attenzione a fare dichiarazioni troppo ampie su OutOfMemoryErrors; c'è un insieme inaspettatamente diversificato di cose che possono causarle.
Tim

3
Come hai risolto il problema ??
Thorsten Niehues,

Risposte:


764

Questo messaggio indica che per qualche motivo il Garbage Collector impiega un tempo eccessivo (per impostazione predefinita il 98% di tutto il tempo della CPU del processo) e recupera pochissima memoria in ogni esecuzione (per impostazione predefinita il 2% dell'heap).

Ciò significa effettivamente che il tuo programma smette di fare qualsiasi progresso ed è sempre impegnato a eseguire solo la garbage collection.

Per impedire all'applicazione di assorbire il tempo della CPU senza fare nulla, JVM lancia questo in Errormodo da avere la possibilità di diagnosticare il problema.

I rari casi in cui l'ho visto accadere sono quelli in cui alcuni codici creavano tonnellate di oggetti temporanei e tonnellate di oggetti debolmente referenziati in un ambiente già molto limitato dalla memoria.

Consulta la guida all'ottimizzazione GC Java, disponibile per varie versioni di Java e contiene sezioni relative a questo problema specifico:


9
Sarebbe corretto riassumere la tua risposta nel modo seguente: "È proprio come un errore" Spazio su heap Java ". Dagli più memoria con -Xmx." ?
Tim Cooper,

58
@ Tim: No, non sarebbe corretto. Dandogli più memoria potrebbe ridurre il problema, dovresti anche guardare il tuo codice e capire perché produce quella quantità di immondizia e perché il tuo codice scorre appena sotto il segno "memoria esaurita". Spesso è un segno di codice non funzionante.
Joachim Sauer,

8
Grazie, sembra che Oracle non sia poi così bravo nella migrazione dei dati, hanno interrotto il collegamento.
Joachim Sauer,

151
Mi avevi in ​​"Grazie, sembra che Oracle non sia poi così bravo"
Rob Grant,

3
@Guus: se più applicazioni vengono eseguite nella stessa JVM, quindi sì, possono facilmente influenzarsi a vicenda. Sarà difficile dire quale si stia comportando male. Separare le applicazioni in JVM distinte potrebbe essere la soluzione più semplice.
Joachim Sauer

215

Citando dall'articolo di Oracle "Java SE 6 HotSpot [tm] Virtual Machine Garbage Collection Tuning" :

Eccessivo tempo GC e OutOfMemoryError

Il raccoglitore parallelo genererà un OutOfMemoryError se si trascorre troppo tempo nella garbage collection: se oltre il 98% del tempo totale viene impiegato nella garbage collection e viene recuperato meno del 2% dell'heap, verrà generato un OutOfMemoryError. Questa funzionalità è progettata per impedire l'esecuzione delle applicazioni per un periodo di tempo prolungato, facendo progressi minimi o nulli poiché l'heap è troppo piccolo. Se necessario, questa funzione può essere disabilitata aggiungendo l'opzione -XX:-UseGCOverheadLimitalla riga di comando.

EDIT: sembra che qualcuno possa digitare più velocemente di me :)


87
"Puoi disattivarlo ..." ma molto probabilmente l'OP non dovrebbe farlo.
Stephen C,

2
Puoi dirmi la differenza tra "-XX" e "-Xmx"? Sono stato in grado di disattivarlo utilizzando anche l'opzione "-Xmx".
Susheel Javadi,

19
In risposta a un commento molto vecchio qui, ma ... @Bart -XX:All'inizio di diverse opzioni della riga di comando è presente una bandiera che indica che questa opzione è altamente specifica per VM e instabile (soggetta a modifiche senza preavviso nelle versioni future). In ogni caso, il -XX:-UseGCOverheadLimitflag indica alla VM di disabilitare il controllo dei limiti generali del GC (in realtà "lo spegne"), mentre il -Xmxcomando ha semplicemente aumentato l'heap. In quest'ultimo caso, il controllo ambientale del GC era ancora in esecuzione , sembra solo che un mucchio più grande abbia risolto i problemi di thrashing del GC nel tuo caso (questo non sempre aiuterà).
Andrzej Doyle,

1
Nella mia applicazione (leggere un grande file Excel in Talend) questo non ha funzionato e dalle spiegazioni degli altri utenti capisco perché. Questo disabilita semplicemente l'errore ma il problema persiste e l'applicazione passerà la maggior parte del tempo a gestire GC. Il nostro server aveva molta RAM, quindi ho usato i suggerimenti di Vitalii per aumentare le dimensioni dell'heap.
RobbZ

Alla fine otterrai questo errore se la tua applicazione è ad alta intensità di dati, svuotare la memoria ed eludere la perdita di dati è la soluzione migliore, ma richiede del tempo.
Pievis,

89

Se sei sicuro che non ci siano perdite di memoria nel tuo programma, prova a:

  1. Aumenta la dimensione dell'heap, ad esempio -Xmx1g.
  2. Abilita il collector con pause basse simultanee -XX:+UseConcMarkSweepGC.
  3. Riutilizzare gli oggetti esistenti quando possibile per risparmiare un po 'di memoria.

Se necessario, è possibile disabilitare il controllo dei limiti aggiungendo l'opzione -XX:-UseGCOverheadLimitalla riga di comando.


9
Non sono d'accordo con il terzo consiglio. Riutilizzare gli oggetti esistenti non consente di risparmiare memoria (non perdere oggetti vecchi per risparmiare memoria :-) Inoltre, "riutilizzare oggetti esistenti" era una pratica per alleviare la pressione GC. Ma non è sempre una buona idea: con GC moderna, dovremmo evitare situazioni in cui vecchi oggetti contengono quelli nuovi, perché si può rompere alcune ipotesi di località ...
mcoolive

@mcoolive: per un esempio un po 'inventato, vedere i commenti per rispondere a stackoverflow.com/a/5640498/4178262 di seguito; la creazione Listdell'oggetto all'interno del loop ha comportato la chiamata di GC 39 volte anziché 22 volte.
Mark Stewart,

45

Di solito è il codice. Ecco un semplice esempio:

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

Utilizzo di Java 1.6.0_24-b07 su Windows 7 a 32 bit.

java -Xloggc:gc.log GarbageCollector

Quindi guarda gc.log

  • Attivato 444 volte usando il metodo BAD
  • Attivato 666 volte usando il metodo WORSE
  • Attivato 354 volte usando il metodo MIGLIORE

Ora concesso, questo non è il miglior test o il miglior design, ma di fronte a una situazione in cui non hai altra scelta che implementare un tale ciclo o quando si tratta di codice esistente che si comporta male, la scelta di riutilizzare gli oggetti invece di crearne di nuovi può ridurre il numero di volte che il garbage collector si mette in mezzo ...


12
Si prega di chiarire: quando si dice "Attivato n volte", significa che si è verificato un GC regolare n volte o che l'errore "Limite di sovraccarico GC superato" è stato segnalato dall'OP si è verificato n volte?
Jon Schneider,

Ho provato proprio ora usando java 1.8.0_91 e non ho mai avuto un errore / eccezione, e il "Triggered n times" è stato dal conteggio del numero di righe nel gc.logfile. I miei test mostrano un numero complessivo di volte inferiore, ma un minor numero di volte "Trigger" per MEGLIO, e ora, BAD è "più cattivo" di PEGGIORE ora. I miei conti: MALE: 26, PEGGIORE: 22, MEGLIO 21.
Mark Stewart

Ho appena aggiunto una modifica "WORST_YET" dove definisco l' List<Double> listnel ciclo esterno invece che prima del ciclo esterno, ed ha innescato 39 garbage collection.
Mark Stewart,

36

Causa dell'errore secondo la piattaforma Java [8], Guida alla risoluzione dei problemi dell'edizione standard : (enfasi e interruzioni di riga aggiunte)

[...] "Limite di sovraccarico GC superato" indica che Garbage Collector è sempre in esecuzione e il programma Java sta facendo progressi molto lenti.

Dopo una garbage collection, se il processo Java impiega più del 98% circa del suo tempo a eseguire la garbage collection e se sta recuperando meno del 2% dell'heap e ha fatto finora gli ultimi 5 (costanti di tempo di compilazione) di immondizia consecutiva raccolte, quindi java.lang.OutOfMemoryErrorviene generata una a. [...]

  1. Aumenta la dimensione dell'heap se l'heap corrente non è sufficiente.
  2. Se l'errore persiste anche dopo aver aumentato la memoria heap, utilizzare gli strumenti di profilazione della memoria come MAT (strumento di analisi della memoria), Visual VM ecc. E correggere le perdite di memoria.
  3. Aggiorna la versione JDK all'ultima versione (1.8.x) o almeno 1.7.xe usa l'algoritmo G1GC. . L'obiettivo di throughput per il GC G1 è il 90% dei tempi di applicazione e il 10% dei tempi di raccolta dei rifiuti
  4. Oltre a impostare la memoria heap con - Xms1g -Xmx2g, provare

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

Dai un'occhiata ad alcune domande più correlate riguardanti G1GC


29

Aumenta leggermente le dimensioni dell'heap impostando questa opzione in

Esegui → Esegui configurazioni → Argomenti → Argomenti VM

-Xms1024M -Xmx2048M

Xms - per limite minimo

Xmx - per limite massimo


2
Le app Android non hanno argumentstab ... cosa dobbiamo fare per raggiungere questo obiettivo?
Blaze Tama,

3
Per quale strumento è quella risposta? Non era una domanda Eclipse.
Michael Piefel,

3
Non esiste un "limite minimo". -Xms è la dimensione iniziale.
Diego Queiroz,

1
Qual è il massimo del limite massimo che potrebbe essere impostato ??
JPerk,

14

Per me, i seguenti passaggi hanno funzionato:

  1. Apri il eclipse.inifile
  2. Modificare

    -Xms40m
    -Xmx512m

    per

    -Xms512m
    -Xmx1024m
  3. Riavvia Eclipse

Vedere qui


il modo più semplice per risolvere questo problema. Grazie :)
Hamza,

1
file eclipse.ini in jdev?
Abhinaba Basu,

problemi irrisolti anche quando la configurazione è stata modificata in questo.
zionpi,

1
L'OP non ha posto una domanda Eclipse.
Michael Piefel,

1
Questa "risposta" non risponde alla domanda sopra.
Freitags il

13

prova questo

apri il build.gradlefile

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

Funziona alla grande per il simulatore. Qualche idea su come questo influisca sui dispositivi reali? cioè è una buona idea o è solo mascherare il problema? Grazie.
Joshua Pinter,

11

Quanto segue ha funzionato per me. Aggiungi il seguente frammento:

android {
        compileSdkVersion 25
        buildToolsVersion '25.0.1'

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

Sì, quando si utilizza Gradle :)
Alex

4
Come hai potuto pensare che questa sia una soluzione alla sua domanda in generale ? È possibile impostare la dimensione heap 4g che è totalmente arbitraria in una configurazione Gradle per Android facepalm .
Julian L.,

7

aumentare javaMaxHeapsize nel file build.gradle (Modulo: app)

dexOptions {
    javaMaxHeapSize "1g"
}

a (Aggiungi questa riga in gradi)

 dexOptions {
        javaMaxHeapSize "4g"
    }

3

Descrizioni delle dimensioni dell'heap Java (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Imposta la dimensione iniziale dell'heap Java. La dimensione predefinita è 2097152 (2 MB). I valori devono essere multipli e superiori a 1024 byte (1 KB). (Il flag -server aumenta la dimensione predefinita a 32M.)

-Xmn size in bytes

Example : java -Xmx2m

Imposta la dimensione iniziale dell'heap Java per la generazione Eden. Il valore predefinito è 640 K. (Il flag -server aumenta la dimensione predefinita a 2M.)

-Xmx size in bytes

Example : java -Xmx2048m

Imposta la dimensione massima alla quale può crescere l'heap Java. La dimensione predefinita è 64M. (Il flag -server aumenta la dimensione predefinita a 128M.) Il limite massimo di heap è di circa 2 GB (2048 MB).

Formattazione degli argomenti della memoria Java (xms, xmx, xmn)

Quando si imposta la dimensione dell'heap Java, è necessario specificare l'argomento di memoria utilizzando una delle lettere "m" o "M" per MB o "g" o "G" per GB. L'impostazione non funzionerà se si specifica "MB" o "GB". Gli argomenti validi sono i seguenti:

-Xms64m o -Xms64M -Xmx1g o -Xmx1G È inoltre possibile utilizzare 2048 MB per specificare 2 GB Inoltre, assicurarsi di utilizzare solo numeri interi quando si specificano gli argomenti. L'uso di -Xmx512m è un'opzione valida, ma -Xmx0.5g provocherà un errore.

Questo riferimento può essere utile per qualcuno.


2

Puoi anche aumentare l'allocazione di memoria e le dimensioni dell'heap aggiungendo questo al tuo gradle.propertiesfile:

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

Non deve essere 2048 M e 32 g, rendilo grande quanto vuoi.


2

Risolto:
Basta aggiungere
org.gradle.jvmargs=-Xmx1024m
in
gradle.properties
e se non esiste, crearla.


0

Sto lavorando in Android Studio e ho riscontrato questo errore durante il tentativo di generare un APK firmato per il rilascio. Sono stato in grado di creare e testare un APK di debug senza problemi, ma non appena volevo creare un APK di rilascio, il processo di compilazione sarebbe durato per minuti e poi sarebbe terminato con "Errore java.lang.OutOfMemoryError: GC limite ambientale superato ". Ho aumentato le dimensioni dell'heap sia per il compilatore VM sia per il compilatore DEX Android, ma il problema persisteva. Alla fine, dopo molte ore e tazze di caffè, è emerso che il problema era nel mio file 'build.gradle' a livello di app - avevo il parametro 'minifyEnabled' per il tipo di build di rilascio impostato su 'false', di conseguenza eseguendo roba Proguard sul codice che non è stato sottoposto al processo di riduzione del codice (vedere https://developer.android.). Ho cambiato il parametro 'minifyEnabled' in 'true' e la build di rilascio eseguita come un sogno :)

In breve, ho dovuto cambiare il file 'build.gradle' a livello di app da: // ...

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

//...

per

    //...

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

//...

0

Per aumentare la dimensione dell'heap in IntelliJ IDEA seguire le seguenti istruzioni. Ha funzionato per me.

Per gli utenti di Windows,

Vai alla posizione in cui è installato IDE e cerca quanto segue.

idea64.exe.vmoptions

Modifica il file e aggiungi quanto segue.

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

Questo è tutto !!


0

puoi provare ad apportare modifiche alle impostazioni del server facendo riferimento a questa immagine e aumentare le dimensioni della memoria per l'elaborazione delle modifiche al processo evidenziate in giallo

puoi anche apportare modifiche a java heap aprendo cmd-> set _java_opts -Xmx2g
2g (2gigabyte) a seconda della complessità del tuo programma

prova ad usare variabili meno costanti e variabili temporanee

inserisci qui la descrizione dell'immagine


-1

È necessario aumentare la dimensione della memoria in Jdeveloper andare su 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**
)

e

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

4
Queste impostazioni sono specifiche solo per l'IDE locale. Questo non funzionerà per l'ambiente Prod.
Feng,

-1

In Netbeans, può essere utile progettare una dimensione heap massima. Vai a Esegui => Imposta configurazione progetto => Personalizza . Nella finestra Esegui della finestra visualizzata, vai a Opzione VM , compila -Xms2048m -Xmx2048m. Potrebbe risolvere il problema delle dimensioni dell'heap.


-1

Il riavvio del mio MacBook ha risolto questo problema per me.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.