Error java.lang.OutOfMemoryError: límite de sobrecarga del GC excedido

805

Recibo este mensaje de error cuando ejecuto mis pruebas JUnit:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Sé lo que OutOfMemoryErrores, pero ¿qué significa el límite superior de GC? ¿Como puedo resolver esto?

Mnementh
fuente
16
Esto suena muy interesante. Me encantaría que alguien pudiera publicar algún código que genere esto.
Buhb
1
Simplemente encontré el problema, que condujo a un uso excesivo de la memoria, cerca del límite del montón. Una solución simple podría ser simplemente darle más memoria de almacenamiento dinámico al motor Java (-Xmx), pero esto solo ayuda, si la aplicación necesita exactamente tanta memoria, como se estableció el límite de almacenamiento dinámico anterior.
Mnementh
1
@Mnementh, he dado una respuesta aquí, verifique si ayuda stackoverflow.com/questions/11091516/…
lulu
16
@SimonKuang Tenga en cuenta que hay múltiples OutOfMemoryErrorescenarios para los cuales aumentar el montón no es una solución válida: quedarse sin subprocesos nativos y quedarse sin perm gen (que es independiente del montón) son dos ejemplos. Tenga cuidado al hacer declaraciones demasiado amplias sobre OutOfMemoryErrors; Hay un conjunto inesperadamente diverso de cosas que pueden causarlos.
Tim
3
¿Cómo resolviste el problema?
Thorsten Niehues

Respuestas:

764

Este mensaje significa que, por alguna razón, el recolector de basura está tomando una cantidad de tiempo excesiva (por defecto, el 98% de todo el tiempo de CPU del proceso) y recupera muy poca memoria en cada ejecución (por defecto, el 2% del montón).

Esto significa que su programa deja de progresar y está ocupado ejecutando solo la recolección de basura en todo momento.

Para evitar que su aplicación absorba el tiempo de CPU sin hacer nada, la JVM lanza esto Errorpara que tenga la oportunidad de diagnosticar el problema.

Los casos raros en los que he visto que esto sucede es cuando algún código creaba toneladas de objetos temporales y toneladas de objetos con referencias débiles en un entorno que ya tiene mucha memoria.

Consulte la guía de ajuste de Java GC, que está disponible para varias versiones de Java y contiene secciones sobre este problema específico:

Joachim Sauer
fuente
99
¿Sería correcto resumir su respuesta de la siguiente manera: "Es como un error 'Fuera del espacio de almacenamiento dinámico de Java'. Déle más memoria con -Xmx". ?
Tim Cooper
58
@Tim: No, eso no sería correcto. Si bien darle más memoria podría reducir el problema, también debe mirar su código y ver por qué produce esa cantidad de basura y por qué su código se desliza justo debajo de la marca "sin memoria". A menudo es una señal de código roto.
Joachim Sauer
8
Gracias, parece que Oracle no es realmente tan bueno en la migración de datos, rompieron el enlace.
Joachim Sauer el
151
Me tenías en "Gracias, parece que Oracle no es realmente tan bueno"
Rob Grant
3
@Guus: si se ejecutan varias aplicaciones en la misma JVM, entonces sí, pueden influenciarse fácilmente entre sí. Será difícil saber cuál se está portando mal. Separar las aplicaciones en distintas JVM podría ser la solución más fácil.
Joachim Sauer
215

Citando el artículo de Oracle "Java SE 6 HotSpot [tm] Virtual Machine Garbage Collection Tuning" :

Tiempo de GC excesivo y OutOfMemoryError

El recolector paralelo lanzará un OutOfMemoryError si se pasa demasiado tiempo en la recolección de basura: si se gasta más del 98% del tiempo total en la recolección de basura y se recupera menos del 2% del montón, se arrojará un OutOfMemoryError. Esta característica está diseñada para evitar que las aplicaciones se ejecuten durante un período prolongado de tiempo mientras progresa poco o nada porque el montón es demasiado pequeño. Si es necesario, esta característica se puede deshabilitar agregando la opción -XX:-UseGCOverheadLimita la línea de comando.

EDITAR: parece que alguien puede escribir más rápido que yo :)

Dave
fuente
87
"Puedes desactivar esto ..." pero el OP probablemente no debería hacer esto.
Stephen C
2
¿Me puede decir la diferencia entre "-XX" y "-Xmx"? Pude apagarlo usando la opción "-Xmx" también.
Susheel Javadi
19
En respuesta a un comentario muy antiguo aquí, pero ... @Bart Al -XX:comienzo de varias opciones de línea de comando hay una especie de indicador que indica que esta opción es altamente específica de VM e inestable (sujeta a cambios sin previo aviso en futuras versiones). En cualquier caso, el -XX:-UseGCOverheadLimitindicador le dice a la VM que deshabilite la comprobación del límite de sobrecarga del GC (en realidad "lo apaga"), mientras que su -Xmxcomando simplemente aumentó el montón. En el último caso, la comprobación general de GC todavía se estaba ejecutando , solo parece que un montón más grande resolvió los problemas de agitación de GC en su caso (esto no siempre ayudará).
Andrzej Doyle
1
En mi aplicación (leer un gran archivo de Excel en Talend) esto no funcionó y la explicación de otros usuarios entiendo por qué. Esto simplemente deshabilita el error, pero el problema persiste y su aplicación solo pasará la mayor parte de su tiempo manejando GC. Nuestro servidor tenía mucha RAM, así que utilicé las sugerencias de Vitalii para aumentar el tamaño del almacenamiento dinámico.
RobbZ
Eventualmente obtendrá este error si su aplicación requiere una gran cantidad de datos, borrar la memoria y evadir la fuga de datos es la mejor salida, pero requiere algo de tiempo.
Pievis 01 de
89

Si está seguro de que no hay pérdidas de memoria en su programa, intente:

  1. Aumente el tamaño del montón, por ejemplo -Xmx1g.
  2. Habilite el recopilador simultáneo de pausa baja -XX:+UseConcMarkSweepGC.
  3. Reutilice los objetos existentes cuando sea posible para ahorrar algo de memoria.

Si es necesario, la verificación del límite se puede deshabilitar agregando la opción -XX:-UseGCOverheadLimita la línea de comando.

Vitalii Fedorenko
fuente
99
No estoy de acuerdo con el tercer consejo. Reutilizar objetos existentes no ahorra memoria (no pierda objetos viejos, guarde memoria :-) Además, "reutilizar objeto existente" era una práctica para aliviar la presión del GC. Pero no siempre es una buena idea: con GC moderna, debemos evitar situaciones en las que los objetos antiguos tienen otras nuevas, ya que puede romper algunos supuestos localidad ...
mcoolive
@mcoolive: para ver un ejemplo un tanto artificial, vea los comentarios para responder stackoverflow.com/a/5640498/4178262 a continuación; La creación del Listobjeto dentro del bucle provocó que GC se llamara 39 veces en lugar de 22 veces.
Mark Stewart el
45

Suele ser el código. Aquí hay un ejemplo simple:

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

Usando Java 1.6.0_24-b07 en un Windows 7 de 32 bits.

java -Xloggc:gc.log GarbageCollector

Entonces mira gc.log

  • Se activó 444 veces con el método MALO
  • Se disparó 666 veces usando el método PEOR
  • Se activó 354 veces con el método MEJOR

Ahora concedido, esta no es la mejor prueba o el mejor diseño, pero cuando se enfrenta a una situación en la que no tiene más remedio que implementar dicho ciclo o cuando se trata de código existente que se comporta mal, elegir reducir los objetos en lugar de crear nuevos puede reducir la cantidad de veces que el recolector de basura se interpone en el camino ...

Miguel
fuente
12
Por favor aclare: Cuando dice "Activado n veces", ¿eso significa que un GC normal ocurrió n veces, o que el error "Límite superior de GC excedido" informado por el OP ocurrió n veces?
Jon Schneider
Lo probé justo ahora usando java 1.8.0_91 y nunca recibí un error / excepción, y el "Disparo n veces" fue de contar el número de líneas en el gc.logarchivo. Mis pruebas muestran muchas menos veces en general, pero pocos tiempos de "Disparadores" para MEJOR, y ahora, MALO es "más malo" que lo PEOR ahora. Mis cuentas: MALO: 26, PEOR: 22, MEJOR 21.
Mark Stewart
Acabo de agregar una modificación "WORST_YET" donde defino List<Double> listen el bucle externo en lugar de antes del bucle externo, y activé 39 recolecciones de basura.
Mark Stewart el
36

Causa del error de acuerdo con la plataforma Java [8], Guía de solución de problemas de la edición estándar : (énfasis y saltos de línea agregados)

[...] "Límite superior de GC excedido" indica que el recolector de basura se está ejecutando todo el tiempo y que el programa Java está progresando muy lentamente.

Después de una recolección de basura, si el proceso de Java está gastando más de aproximadamente el 98% de su tiempo haciendo recolección de basura y si está recuperando menos del 2% del montón y ha estado haciendo hasta ahora los últimos 5 (tiempo de compilación constante) basura consecutiva colecciones, luego java.lang.OutOfMemoryErrorse arroja a. [...]

  1. Aumente el tamaño del montón si el montón actual no es suficiente.
  2. Si aún recibe este error después de aumentar la memoria de almacenamiento dinámico, use herramientas de creación de perfiles de memoria como MAT ( herramienta de análisis de memoria), Visual VM, etc. y repare las pérdidas de memoria.
  3. Actualice la versión JDK a la última versión (1.8.x) o al menos 1.7.xy use el algoritmo G1GC. . El objetivo de rendimiento para el GC G1 es 90 por ciento de tiempo de aplicación y 10 por ciento de tiempo de recolección de basura.
  4. Además de configurar la memoria de almacenamiento dinámico con - Xms1g -Xmx2g, intente

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

Eche un vistazo a algunas preguntas más relacionadas con G1GC

Ravindra babu
fuente
29

Simplemente aumente un poco el tamaño del montón configurando esta opción en

Ejecutar → Ejecutar configuraciones → Argumentos → Argumentos de VM

-Xms1024M -Xmx2048M

Xms - para límite mínimo

Xmx - para límite máximo

chopss
fuente
2
Las aplicaciones de Android no tienen argumentspestaña ... ¿qué debemos hacer para lograr esto?
Blaze Tama
3
¿Para qué herramienta es esa respuesta? Esa no era una pregunta de Eclipse.
Michael Piefel
3
No hay "límite mínimo". -Xms es el tamaño inicial.
Diego Queiroz
1
¿Cuál es el límite máximo máximo que se puede establecer?
JPerk
14

Para mí, los siguientes pasos funcionaron:

  1. Abrir el eclipse.iniarchivo
  2. Cambio

    -Xms40m
    -Xmx512m

    a

    -Xms512m
    -Xmx1024m
  3. Reiniciar Eclipse

Mira aquí

Sunil Kumar Sahoo
fuente
La forma más sencilla de solucionar este problema. Gracias :)
Hamza
1
archivo eclipse.ini en jdev?
Abhinaba Basu
problemas sin resolver incluso cuando la configuración se ha cambiado a esto.
zionpi
1
El OP no hizo una pregunta de Eclipse.
Michael Piefel
1
Esta "respuesta" no responde la pregunta anterior.
Freitags
13

prueba esto

abre el build.gradlearchivo

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }
alicanozkara
fuente
Funciona muy bien para el simulador. ¿Alguna idea de cómo esto afecta a los dispositivos reales? es decir, ¿es una buena idea o solo está enmascarando el problema? Gracias.
Joshua Pinter
11

Lo siguiente funcionó para mí. Simplemente agregue el siguiente fragmento:

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
fuente
Sí, cuando se usa Gradle :)
Alex
44
¿Cómo podría incluso pensar que esta es una solución a su pregunta en general ? Establece su tamaño de almacenamiento dinámico en 4g, que es totalmente arbitrario en una configuración de gradle para Android facepalm .
Julian L.
7

aumente javaMaxHeapsize en su archivo build.gradle (Módulo: aplicación)

dexOptions {
    javaMaxHeapSize "1g"
}

a (Agregar esta línea en gradle)

 dexOptions {
        javaMaxHeapSize "4g"
    }
Sai Gopi N
fuente
3

Descripciones de tamaño de almacenamiento dinámico de Java (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Establece el tamaño inicial del montón de Java. El tamaño predeterminado es 2097152 (2 MB). Los valores deben ser múltiplos de, y mayores que, 1024 bytes (1 KB). (El indicador -server aumenta el tamaño predeterminado a 32M).

-Xmn size in bytes

Example : java -Xmx2m

Establece el tamaño de almacenamiento dinámico Java inicial para la generación Eden. El valor predeterminado es 640K. (El indicador de servidor aumenta el tamaño predeterminado a 2M).

-Xmx size in bytes

Example : java -Xmx2048m

Establece el tamaño máximo al que puede crecer el montón de Java. El tamaño predeterminado es 64M. (El indicador -server aumenta el tamaño predeterminado a 128M.) El límite máximo de almacenamiento dinámico es de aproximadamente 2 GB (2048MB).

Formato de argumentos de memoria Java (xms, xmx, xmn)

Al configurar el tamaño de almacenamiento dinámico de Java, debe especificar su argumento de memoria utilizando una de las letras "m" o "M" para MB, o "g" o "G" para GB. Su configuración no funcionará si especifica "MB" o "GB". Los argumentos válidos se ven así:

-Xms64m o -Xms64M -Xmx1g o -Xmx1G También puede usar 2048MB para especificar 2GB Además, asegúrese de usar números enteros al especificar sus argumentos. Usar -Xmx512m es una opción válida, pero -Xmx0.5g causará un error.

Esta referencia puede ser útil para alguien.

Fénix
fuente
2

También puede aumentar la asignación de memoria y el tamaño del montón agregando esto a su gradle.propertiesarchivo:

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

No tiene que ser 2048M y 32g, hazlo tan grande como quieras.

John Doe
fuente
2

Resuelto:
Sólo tiene que añadir
org.gradle.jvmargs=-Xmx1024m
en
gradle.properties
y si no existe, crear.

reza_khalafi
fuente
0

Estoy trabajando en Android Studio y encontré este error al intentar generar un APK firmado para su lanzamiento. Pude compilar y probar un APK de depuración sin problemas, pero tan pronto como quise compilar un APK de lanzamiento, el proceso de compilación se ejecutaría durante minutos y finalmente terminaría con el "Error java.lang.OutOfMemoryError: GC límite superior excedido ". Aumenté los tamaños de almacenamiento dinámico tanto para la VM como para el compilador DEX de Android, pero el problema persistió. Finalmente, después de muchas horas y tazas de café, resultó que el problema estaba en mi archivo 'build.gradle' de nivel de aplicación: tenía el parámetro 'minifyEnabled' para el tipo de compilación de lanzamiento establecido en 'falso', por lo tanto, ejecuté cosas de Proguard en código que no ha pasado por el proceso de reducción de código '(consulte https://developer.android.) Cambié el parámetro 'minifyEnabled' a 'verdadero' y la compilación de lanzamiento se ejecutó como un sueño :)

En resumen, tuve que cambiar mi archivo 'build.gradle' de nivel de aplicación de: // ...

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

//...

a

    //...

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
fuente
0

Para aumentar el tamaño de almacenamiento dinámico en IntelliJ IDEA, siga las siguientes instrucciones. Funcionó para mi.

Para usuarios de Windows,

Vaya a la ubicación donde está instalado IDE y busque lo siguiente.

idea64.exe.vmoptions

Edite el archivo y agregue lo siguiente.

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

Eso es !!

Dulith De Costa
fuente
0

puede intentar realizar cambios en la configuración del servidor haciendo referencia a esta imagen y aumentar el tamaño de la memoria para procesar los cambios del proceso resaltados en amarillo

También puede hacer cambios en Java Heap abriendo cmd-> set _java_opts -Xmx2g
2g (2gigabytes) dependiendo de la complejidad de su programa

intenta usar variables menos constantes y variables temporales

ingrese la descripción de la imagen aquí

Rahul Jain
fuente
-1

Debe aumentar el tamaño de la memoria en Jdeveloper, vaya a 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**
)

y

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
fuente
44
Esta configuración solo es específica de su IDE local. Esto no funcionará para el entorno Prod.
Feng
-1

En Netbeans, puede ser útil diseñar un tamaño de almacenamiento dinámico máximo. Vaya a Ejecutar => Establecer configuración del proyecto => Personalizar . En el Ejecutar de su ventana emergente, vaya a la Opción VM , complete -Xms2048m -Xmx2048m. Podría resolver el problema del tamaño del montón.

Xiaogang
fuente
-1

Reiniciar mi MacBook solucionó este problema por mí.

Thomas
fuente