Tratamiento del error "java.lang.OutOfMemoryError: espacio PermGen"

1222

Recientemente me encontré con este error en mi aplicación web:

java.lang.OutOfMemoryError: espacio PermGen

Es una aplicación típica de Hibernate / JPA + IceFaces / JSF que se ejecuta en Tomcat 6 y JDK 1.6. Aparentemente, esto puede ocurrir después de volver a implementar una aplicación varias veces.

¿Qué lo causa y qué se puede hacer para evitarlo? ¿Cómo soluciono el problema?

Chris
fuente
He luchado contra esto durante horas, pero no tengo buenas noticias. Consulte mi pregunta relacionada: stackoverflow.com/questions/1996088/… Es posible que aún tenga una pérdida de memoria, por ejemplo, las clases no se recolectan basura porque su WebAppClassLoader no se recolecta basura (tiene una referencia externa que no se borra). aumentar el PermGen solo retrasará el OutOfMemoryError, y permitir la recolección de basura de clase es una condición previa, pero no recolectará basura si su cargador de clases aún tiene referencias a él.
Eran Medan
Recibí este error al agregar display taglib . Eliminar también resolvió el error. ¿Porque?
masT
¿Y cómo te topaste con eso?
Thorbjørn Ravn Andersen
13
use JDK 1.8: þ bienvenido al MetaSpace
Rytek
Si usa Windows, siga estas instrucciones en lugar de intentar establecer los marcadores manualmente en los archivos de configuración. Esto establece correctamente los valores en el registro que Tomcat llamará durante el tiempo de ejecución. stackoverflow.com/questions/21104340/…
MacGyver

Respuestas:

563

La solución fue agregar estos indicadores a la línea de comandos de JVM cuando se inicia Tomcat:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Puede hacerlo cerrando el servicio tomcat, yendo al directorio Tomcat / bin y ejecutando tomcat6w.exe. En la pestaña "Java", agregue los argumentos al cuadro "Opciones de Java". Haga clic en "Aceptar" y luego reinicie el servicio.

Si obtiene un error, el servicio especificado no existe como un servicio instalado que debe ejecutar:

tomcat6w //ES//servicename

donde servicename es el nombre del servidor como se ve en services.msc

Fuente: comentario de orx sobre las respuestas ágiles de Eric .

Chris
fuente
39
El siguiente artículo sugiere -XX: + UseConcMarkSweepGC y -XX: MaxPermSize = 128m también. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese
30
-XX: + CMSPermGenSweepingEnabled Esta opción reduce el rendimiento. Hace que cada solicitud tome tres veces más tiempo de lo habitual en nuestros sistemas. Usar con cuidado.
Eldelshell
10
funcionó para mí, gracias. Estoy haciendo esto en Ubuntu 10.10 con Tomcat6. Creé un nuevo archivo: /usr/share/tomcat6/bin/setenv.sh y agregué la siguiente línea: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Tomcat reiniciado usando: sudo /etc/init.d/tomcat6 start
sami
24
En el inicio de tomcat 6.0.29, desde mi archivo de registro catalina.out: "Utilice CMSClassUnloadingEnabled en lugar de CMSPermGenSweepingEnabled en el futuro"
knb
222
En primer lugar, sería genial explicar qué hacen realmente estas banderas. Solo decir: "haz eso y disfruta" no es suficiente en mi humilde opinión.
Nikem
251

Será mejor que lo intentes en -XX:MaxPermSize=128Mlugar de hacerlo -XX:MaxPermGen=128M.

No puedo decir el uso preciso de este grupo de memoria, pero tiene que ver con el número de clases cargadas en la JVM. (Por lo tanto, habilitar la descarga de clases para tomcat puede resolver el problema). Si sus aplicaciones generan y compilan clases en ejecución, es más probable que necesite un grupo de memoria más grande que el predeterminado.

toesterdahl
fuente
99
En realidad, esto solo pospondrá OOMError. Vea la respuesta a continuación iniciada por anon con dos enlaces al blog frankkieviet.
Rade_303
Estas opciones se explican aquí: oracle.com/technetwork/java/javase/tech/…
amos
153

Los errores de PermGen del servidor de aplicaciones que ocurren después de múltiples implementaciones probablemente sean causados ​​por las referencias que el contenedor contiene en los cargadores de clases de sus aplicaciones anteriores. Por ejemplo, el uso de una clase de nivel de registro personalizada hará que las referencias sean retenidas por el cargador de clases del servidor de aplicaciones. Puede detectar estas fugas entre cargadores entre clases utilizando herramientas modernas de análisis JVM (JDK6 +) como jmap y jhat para ver qué clases continúan en su aplicación y rediseñando o eliminando su uso. Los sospechosos habituales son bases de datos, registradores y otras bibliotecas de nivel de marco base.

Consulte las filtraciones de Classloader: la temida excepción "java.lang.OutOfMemoryError: PermGen space" , y especialmente su publicación de seguimiento .

anon
fuente
3
Esta es solo una verdadera solución al problema, capaz en algunos casos de ser demasiado difícil de implementar.
Rade_303
Otra muy buena fuente es people.apache.org/~markt/presentations/… (¡del administrador de versiones de Tomcat!).
gavenkoa
22
Si bien esto puede responder teóricamente la pregunta, sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace para referencia.
Joachim Sauer
68

Los errores comunes que cometen las personas es pensar que el espacio de almacenamiento dinámico y el espacio permgen son iguales, lo cual no es del todo cierto. Podría tener mucho espacio restante en el montón, pero aún puede quedarse sin memoria en permgen.

Las causas comunes de OutofMemory en PermGen es ClassLoader. Cada vez que se carga una clase en JVM, todos sus metadatos, junto con Classloader, se mantienen en el área de PermGen y se recolectarán cuando el Classloader que los cargó esté listo para la recolección de basura. En el caso, Classloader tiene una pérdida de memoria que todas las clases cargadas permanecerán en la memoria y causarán que permGen quede fuera de memoria una vez que lo repita un par de veces. El ejemplo clásico es Java.lang.OutOfMemoryError: PermGen Space en Tomcat .

Ahora hay dos formas de resolver esto:
1. Encuentre la causa de la pérdida de memoria o si hay alguna pérdida de memoria.
2. Aumente el tamaño del espacio PermGen utilizando JVM param -XX:MaxPermSizey -XX:PermSize.

También puede consultar 2 Solution of Java.lang.OutOfMemoryError en Java para obtener más detalles.

Peter
fuente
3
¿Cómo pasar param -XX:MaxPermSize and -XX:PermSize? No puedo encontrar catalina.bat. Mi versión de Tomcat es 5.5.26.
Deckard
¿Cómo encontrar las pérdidas de memoria del cargador de clases? ¿Recomiendas alguna herramienta?
Amit
@amit para recomendaciones de herramientas, vea la respuesta wiki de la comunidad sobre esta pregunta.
Barett
@Deckard va al directorio Tomcat / bin y ejecuta tomcat6w.exe. En la pestaña "Java", agregue los argumentos al cuadro "Opciones de Java". Haga clic en "Aceptar"
Zeb
43

Utilice el parámetro de línea de comando -XX:MaxPermSize=128mpara una JVM de Sun (obviamente sustituyendo 128 por el tamaño que necesite).

usuario17163
fuente
99
El único problema es que solo está retrasando lo inevitable: en algún momento también se quedará sin espacio para la cabeza. Es una gran solución pragmática, pero no la resuelve permanentemente.
Tim Howland
Lo mismo ocurre en Eclipse y cada vez que tiene mucha carga de clase dinámica. los cargadores de clases no están dispuestos y viven en la generación permanente por toda la eternidad
Matt
1
Me estaba quedando sin PermGen cuando ejecutaba un trabajo Hudson particularmente grande ... esto me lo arregló.
HDave
10
@TimHowland, puede ser una solución permanente si la causa raíz no es la fuga del cargador de clases, solo demasiadas clases / datos estáticos en su aplicación web.
Péter Török
tiene el mismo problema que HDave al construir jenkins / hudson desde la fuente.
louisgab
38

Intenta -XX:MaxPermSize=256my si persiste, prueba-XX:MaxPermSize=512m

bajista
fuente
56
y si aún persiste intente XX:MaxPermSize=1024m:)
igo
38
y si aún persiste, prueba XX: MaxPermSize = 2048m :)
Thomas
16
¡Y si TODAVÍA persiste, reconsidere su aplicación! O prueba XX: MaxPermSize = 4096m :)
Jonathan Airey
17
también puedes probar 8192m, pero eso es un poco exagerado
Jacek Pietal
12
Demasiado exagerado, ¡640KB deberían ser suficientes para cualquiera!
Joel Purra
28

Yo añadí -XX: MaxPermSize = 128m (se puede experimentar lo que funciona mejor) a argumentos de VM como yo estoy usando Eclipse IDE. En la mayoría de JVM, PermSize predeterminado es de alrededor de 64 MB que se queda sin memoria si hay demasiadas clases o una gran cantidad de cadenas en el proyecto.

Para eclipse, también se describe en la respuesta .

PASO 1 : haga doble clic en el servidor Tomcat en la pestaña Servidores

ingrese la descripción de la imagen aquí

PASO 2 : Abra el lanzamiento de Conf y agréguelo -XX: MaxPermSize = 128mal final de los argumentos de VM existentes .

ingrese la descripción de la imagen aquí

prayagupd
fuente
1
Gracias por su mejor respuesta detallada (Nota: haga clic en "Abrir configuración de inicio" para abrir la ventana "editar configuración" ... pero utilicé los siguientes parámetros: "-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled"
Chris Sim
23

Me he estado enfrentando a este problema mientras desplegaba y desplegaba una aplicación web compleja también, y pensé en agregar una explicación y mi solución.

Cuando implemento una aplicación en Apache Tomcat, se crea un nuevo ClassLoader para esa aplicación. El ClassLoader se usa para cargar todas las clases de la aplicación, y en la anulación de la implementación, se supone que todo desaparecerá bien. Sin embargo, en realidad no es tan simple.

Una o más de las clases creadas durante la vida de la aplicación web contienen una referencia estática que, en algún lugar a lo largo de la línea, hace referencia al ClassLoader. Como la referencia es originalmente estática, ninguna cantidad de recolección de basura limpiará esta referencia: el ClassLoader y todas las clases cargadas están aquí para quedarse.

Y después de un par de redespliegues, nos encontramos con OutOfMemoryError.

Ahora esto se ha convertido en un problema bastante serio. Podría asegurarme de que Tomcat se reinicie después de cada nueva implementación, pero eso elimina todo el servidor, en lugar de solo la aplicación que se vuelve a implementar, lo que a menudo no es factible.

Entonces, en su lugar, armé una solución en código, que funciona en Apache Tomcat 6.0. No he probado en ningún otro servidor de aplicaciones, y debo enfatizar que es muy probable que esto no funcione sin modificaciones en ningún otro servidor de aplicaciones .

También me gustaría decir que personalmente odio este código, y que nadie debería usarlo como una "solución rápida" si el código existente se puede cambiar para usar los métodos adecuados de apagado y limpieza . El único momento en que esto debería usarse es si hay una biblioteca externa de la que depende su código (en mi caso, era un cliente RADIUS) que no proporciona un medio para limpiar sus propias referencias estáticas.

De todos modos, adelante con el código. Esto debería llamarse en el punto donde la aplicación se está desplegando, como el método de destrucción de un servlet o (el mejor enfoque) el método contextDestroyed de ServletContextListener.

//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
    try {
        classLoaderClassesField = clazz.getDeclaredField("classes");
    } catch (Exception exception) {
        //do nothing
    }
    clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);

List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));

for (Object o : classes) {
    Class c = (Class)o;
    //Make sure you identify only the packages that are holding references to the classloader.
    //Allowing this code to clear all static references will result in all sorts
    //of horrible things (like java segfaulting).
    if (c.getName().startsWith("com.whatever")) {
        //Kill any static references within all these classes.
        for (Field f : c.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers())
                    && !Modifier.isFinal(f.getModifiers())
                    && !f.getType().isPrimitive()) {
                try {
                    f.setAccessible(true);
                    f.set(null, null);
                } catch (Exception exception) {
                    //Log the exception
                }
            }
        }
    }
}

classes.clear();
Edward Torbett
fuente
Sé que han pasado más de 8 años desde que escribí esto, pero en algún momento entre entonces y ahora encontré una causa raíz más profunda y una solución. Esto fue así, mientras que todas las clases dentro de la aplicación web son propiedad del cargador de clases de contexto, el subproceso que invoca la devolución de llamada de inicio y apagado es propiedad del cargador de clases padre. Esto significa que si el código de apagado inicializa una variable local de subproceso, esto hará que el cargador de clases padre termine manteniendo una referencia al cargador de clases de contexto, evitando una buena limpieza.
Edward Torbett
Afortunadamente, hay una solución muy simple: mover todo el código actualmente en el método de apagado al nuevo método de ejecución del objeto Thread. Luego, en el método de apagado, inicie este hilo y espere a que se complete. El código de limpieza se ejecutará de forma idéntica, pero las variables locales de subprocesos permanecerán vinculadas al cargador de clases de contexto en lugar de filtrarse.
Edward Torbett
20

El java.lang.OutOfMemoryError: PermGenmensaje de espacio indica que el área de la generación permanente en la memoria está agotada.

Cualquier aplicación Java puede utilizar una cantidad limitada de memoria. La cantidad exacta de memoria que puede usar su aplicación particular se especifica durante el inicio de la aplicación.

La memoria Java está separada en diferentes regiones que se pueden ver en la siguiente imagen:

ingrese la descripción de la imagen aquí

Metaspace: nace un nuevo espacio de memoria

El JDK 8 HotSpot JVM ahora está usando memoria nativa para la representación de metadatos de clase y se llama Metaspace; similar a Oracle JRockit e IBM JVM.

La buena noticia es que significa que no habrá más java.lang.OutOfMemoryError: PermGenproblemas de espacio y que ya no tendrá que ajustar y monitorear este espacio de memoria utilizando Java_8_Download o superior.

Santosh Jadi
fuente
17

1) Aumento del tamaño de la memoria PermGen

Lo primero que se puede hacer es aumentar el tamaño del espacio dinámico de generación permanente. Esto no se puede hacer con los argumentos JVM habituales –Xms (establecer el tamaño de almacenamiento dinámico inicial) y –Xmx (establecer el tamaño de almacenamiento dinámico máximo), ya que, como se mencionó, el espacio de almacenamiento dinámico de generación permanente está completamente separado del espacio de almacenamiento dinámico Java normal, y estos argumentos establecen El espacio para este espacio de almacenamiento dinámico Java normal. Sin embargo, existen argumentos similares que pueden usarse (al menos con Sun / OpenJDK jvms) para aumentar el tamaño del montón de generación permanente:

 -XX:MaxPermSize=128m

El valor predeterminado es 64 m.

2) Habilitar barrido

Otra forma de solucionarlo definitivamente es permitir que se descarguen las clases para que su PermGen nunca se agote:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Cosas como esa funcionaron magia para mí en el pasado. Sin embargo, una cosa es que hay un importante rendimiento en el uso de esos, ya que los barridos permgen harán 2 solicitudes adicionales por cada solicitud que realice o algo por el estilo. Tendrá que equilibrar su uso con las compensaciones.

Puede encontrar los detalles de este error.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html

faisalbhagat
fuente
Gran publicación de @faisalbhagat faisalbhagat.blogspot.com/2014/09/…
leomeurer
La opción 2 es excelente, pero tenga en cuenta que no debe usarse en entornos de producción. Por lo general, es mejor mantenerlo solo en entornos de desarrollo. Sin embargo, PermGen se elimina a partir de Java 8 openjdk.java.net/jeps/122
hdost
16

Alternativamente, puede cambiar a JRockit que maneja permgen de manera diferente que jvm de sun. En general, también tiene un mejor rendimiento.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html

Jeremy
fuente
44
Si bien JRockit no tiene PermGen, esto no ayudará a largo plazo. Tendrás en su java.lang.OutOfMemoryError: There is insufficient native memorylugar.
Stracktracer
14

Tuve el problema del que estamos hablando aquí, mi escenario es eclipse-helios + tomcat + jsf y lo que estabas haciendo es implementar una aplicación simple en tomcat. Estaba mostrando el mismo problema aquí, lo resolví de la siguiente manera.

En eclipse, vaya a la pestaña de servidores, haga doble clic en el servidor registrado en mi caso tomcat 7.0, se abre la información de registro general de mi servidor de archivos. En la sección "Información general", haga clic en el enlace "Abrir configuración de inicio" , esto abre la ejecución de las opciones del servidor en la pestaña Argumentos en los argumentos de VM agregados al final de estas dos entradas

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

y listo.

Hugo Mendoza
fuente
14

La respuesta más simple en estos días es usar Java 8.

Ya no reserva memoria exclusivamente para el espacio PermGen, permitiendo que la memoria PermGen se mezcle con el grupo de memoria normal.

Tenga en cuenta que tendrá que eliminar todos los -XXPermGen...=...parámetros de inicio JVM no estándar si no desea que Java 8 se queje de que no hacen nada.

Edwin Buck
fuente
Hola, esta respuesta ya se ha dado: stackoverflow.com/a/22897121/505893 . Por favor, elimine su respuesta, para mayor claridad. Si es necesario, podría mejorar la respuesta que mencioné. Gracias;)
azulado
66
@ azulado Gracias por señalar eso; sin embargo, esa respuesta va de un lado a otro al hablar de OutOfMemoryExceptions y filtrar metadatos. Tampoco menciona los puntos muy importantes de eliminar la opción PermGen. En resumen, no estoy seguro de mejorar la respuesta, sino de reescribirla. Si fuera solo un retoque rápido, me sentiría menos vacilante, pero parece que sería mucho más que un retoque rápido, y odiaría ofender al autor original. Aún así, esta lista de respuestas es la cena de un desastre de perros, y quizás matar mi publicación sería lo mejor de todos modos.
Edwin Buck
8
  1. Abra tomcat7w desde el directorio bin de Tomcat o escriba Monitor Tomcat en el menú de inicio (se abre una ventana con pestañas con diversa información de servicio).
  2. En el área de texto Opciones de Java, agregue esta línea:

    -XX:MaxPermSize=128m
  3. Establezca el conjunto de memoria inicial en 1024 (opcional).
  4. Establezca el conjunto de memoria máxima en 1024 (opcional).
  5. Haga clic en Aceptar.
  6. Reinicie el servicio Tomcat.
Lucky
fuente
6

El error de espacio de generación permanente ocurre debido al uso de espacio grande en lugar de jvm proporcionó espacio para ejecutar el código.

La mejor solución para este problema en los sistemas operativos UNIX es cambiar alguna configuración en el archivo bash. Los siguientes pasos resuelven el problema.

Ejecute el comando gedit .bashrcen la terminal.

Crear JAVA_OTPSvariable con el siguiente valor:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

Guarda el archivo bash. Ejecute el comando exec bash en la terminal. Reinicia el servidor.

Espero que este enfoque funcione en su problema. Si utiliza una versión de Java inferior a 8, este problema se produce a veces. Pero si usa Java 8, el problema nunca se produce.

Darshan
fuente
5

Aumentar el tamaño de la generación permanente o ajustar los parámetros del GC NO ayudará si tiene una pérdida de memoria real. Si su aplicación o alguna biblioteca de terceros que utiliza, filtra los cargadores de clases, la única solución real y permanente es encontrar esta filtración y solucionarla. Hay varias herramientas que pueden ayudarlo, una de las recientes es Plumbr , que acaba de lanzar una nueva versión con las capacidades requeridas.

Nikem
fuente
5

Además, si está utilizando log4j en su aplicación web, consulte este párrafo en la documentación de log4j .

Parece que si está utilizando PropertyConfigurator.configureAndWatch("log4j.properties"), puede causar pérdidas de memoria cuando desinstala su aplicación web.

sermojohn
fuente
4

Tengo una combinación de Hibernate + Eclipse RCP, intenté usar -XX:MaxPermSize=512my -XX:PermSize=512mparece estar funcionando para mí.

Pankaj Shinde
fuente
4

Conjunto -XX:PermSize=64m -XX:MaxPermSize=128m. Más adelante también puede intentar aumentar MaxPermSize. Espero que funcione. Lo mismo funciona para mí. La configuración solo MaxPermSizeno funcionó para mí.

sandeep
fuente
4

Intenté varias respuestas y lo único que finalmente hizo el trabajo fue esta configuración para el complemento del compilador en el pom:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <fork>true</fork>
        <meminitial>128m</meminitial>
        <maxmem>512m</maxmem>
        <source>1.6</source>
        <target>1.6</target>
        <!-- prevent PermGen space out of memory exception -->
        <!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
    </configuration>
</plugin>

Espero que esto ayude.

kiwilisk
fuente
"argLine" no es reconocido por maven-compiler-plugin 2.4. solo admite "compilerArgument", que proporciona el error: <compilerArgument> -XX: MaxPermSize = 256m </compilerArgument> [ERROR] Error al ejecutar javac, pero no pudo analizar el error: javac: indicador no válido: -XX: MaxPermSize = 256m Uso : javac <opciones> <archivos fuente>
Alex
Si su fase de compilación se está quedando sin permgen, configure el <compilerArgument> en el plugin maven-compiler. Si las pruebas unitarias se están quedando sin PermGen conjunto <argLine> en el experto-segura-plugin
QWERTY
4

resolvió esto por mí también; Sin embargo, noté que los tiempos de reinicio del servlet eran mucho peores, por lo que si bien fue mejor en producción, fue un obstáculo para el desarrollo.

Tim Howland
fuente
3

La configuración de la memoria depende de la naturaleza de su aplicación.

¿Qué estás haciendo?

¿Cuál es la cantidad de transacciones precesadas?

¿Cuántos datos estás cargando?

etc.

etc.

etc.

Probablemente podría perfilar su aplicación y comenzar a limpiar algunos módulos de su aplicación.

Aparentemente, esto puede ocurrir después de volver a implementar una aplicación varias veces

Tomcat tiene despliegue en caliente pero consume memoria. Intente reiniciar su contenedor de vez en cuando. También necesitará saber la cantidad de memoria necesaria para ejecutar en modo de producción, este parece ser un buen momento para esa investigación.

OscarRyz
fuente
3

Dicen que la última versión de Tomcat (6.0.28 o 6.0.29) maneja la tarea de volver a desplegar servlets mucho mejor.

Tony Ennis
fuente
3

Me encuentro exactamente con el mismo problema, pero desafortunadamente ninguna de las soluciones sugeridas realmente funcionó para mí. El problema no ocurrió durante la implementación, y tampoco estaba haciendo implementaciones en caliente.

En mi caso, el problema ocurrió cada vez en el mismo punto durante la ejecución de mi aplicación web, mientras me conectaba (a través de hibernación) a la base de datos.

Este enlace (también mencionado anteriormente) proporcionó suficientes elementos internos para resolver el problema. Mover el controlador jdbc- (mysql) fuera de WEB-INF y hacia la carpeta jre / lib / ext / parece haber resuelto el problema. Esta no es la solución ideal, ya que actualizar a un JRE más nuevo requeriría que reinstale el controlador. Otro candidato que podría causar problemas similares es log4j, por lo que es posible que desee mover ese también

2 revoluciones
fuente
Si no desea incluir el controlador en jre / lib / ext, probablemente podría obtener los mismos resultados si incluye el controlador en su classpath de inicio del contenedor. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar container.Start
Scot
3

El primer paso en tal caso es verificar si el GC puede descargar clases de PermGen. La JVM estándar es bastante conservadora a este respecto: las clases nacen para vivir para siempre. Entonces, una vez cargadas, las clases permanecen en la memoria incluso si ya no las usa ningún código. Esto puede convertirse en un problema cuando la aplicación crea muchas clases dinámicamente y las clases generadas no son necesarias por períodos más largos. En tal caso, puede ser útil permitir que la JVM descargue definiciones de clase. Esto se puede lograr agregando solo un parámetro de configuración a sus scripts de inicio:

-XX:+CMSClassUnloadingEnabled

De forma predeterminada, esto se establece en falso y, por lo tanto, para habilitarlo, debe establecer explícitamente la siguiente opción en las opciones de Java. Si habilita CMSClassUnloadingEnabled, GC también barrerá PermGen y eliminará las clases que ya no se usan. Tenga en cuenta que esta opción solo funcionará cuando UseConcMarkSweepGC también esté habilitado usando la opción a continuación. Entonces, cuando ejecute ParallelGC o, Dios no lo quiera, Serial GC, asegúrese de haber configurado su GC en CMS especificando:

-XX:+UseConcMarkSweepGC
sendon1982
fuente
3

Asignar más memoria a Tomcat NO es la solución adecuada.

La solución correcta es hacer una limpieza después de que el contexto se destruya y se vuelva a crear (la implementación en caliente). La solución es detener las pérdidas de memoria.

Si su servidor Tomcat / Webapp le indica que no pudo anular el registro de los controladores (JDBC), anule el registro. Esto detendrá las pérdidas de memoria.

Puede crear un ServletContextListener y configurarlo en su web.xml. Aquí hay un ejemplo de ServletContextListener:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;

import com.mysql.jdbc.AbandonedConnectionCleanupThread;

/**
 * 
 * @author alejandro.tkachuk / calculistik.com
 *
 */
public class AppContextListener implements ServletContextListener {

    private static final Logger logger = Logger.getLogger(AppContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        logger.info("AppContextListener started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        logger.info("AppContextListener destroyed");

        // manually unregister the JDBC drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("Unregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error unregistering driver %s", driver), e);
            }

        }

        // manually shutdown clean up threads
        try {
            AbandonedConnectionCleanupThread.shutdown();
            logger.info("Shutting down AbandonedConnectionCleanupThread");
        } catch (InterruptedException e) {
            logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
            e.printStackTrace();
        }        
    }
}

Y aquí lo configura en su web.xml:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>  
Alejandro Pablo Tkachuk
fuente
2

"Ellos" están equivocados porque estoy ejecutando 6.0.29 y tengo el mismo problema incluso después de configurar todas las opciones. Como Tim Howland dijo anteriormente, estas opciones solo posponen lo inevitable. Me permiten volver a implementar 3 veces antes de dar con el error en lugar de cada vez que vuelvo a implementar.

Pueblos Ross
fuente
2

En caso de que obtenga esto en el eclipse IDE, incluso después de configurar los parámetros --launcher.XXMaxPermSize , -XX:MaxPermSizeetc., aún si obtiene el mismo error, lo más probable es que el eclipse esté utilizando una versión defectuosa de JRE que habría sido instalada por algunos aplicaciones de terceros y configuradas por defecto. Estas versiones con errores no recogen los parámetros de PermSize y, por lo tanto, no importa lo que establezca, seguirá recibiendo estos errores de memoria. Entonces, en su eclipse.ini agregue los siguientes parámetros:

-vm <path to the right JRE directory>/<name of javaw executable>

También asegúrese de establecer el JRE predeterminado en las preferencias en el eclipse a la versión correcta de Java.

Hrishikesh Kumar
fuente
2

La única forma que funcionó para mí fue con JRockit JVM. Tengo MyEclipse 8.6.

El montón de JVM almacena todos los objetos generados por un programa Java en ejecución. Java utiliza el newoperador para crear objetos, y la memoria para nuevos objetos se asigna en el montón en tiempo de ejecución. La recolección de basura es el mecanismo de liberar automáticamente la memoria contenida en los objetos a los que el programa ya no hace referencia.

usuario1985910
fuente
2

Estaba teniendo un problema similar. El mío es JDK 7 + Maven 3.0.2 + Struts 2.0 + Proyecto basado en inyección de dependencia de Google GUICE.

Cada vez que intentaba ejecutar mvn clean packagecomandos, se muestra siguiente error y "FALLO construir" producido

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; la excepción anidada es java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Causada por: java.lang.OutOfMemoryError: PermGen space

Intenté todos los consejos y trucos útiles anteriores, pero desafortunadamente ninguno funcionó para mí. Lo que funcionó para mí se describe paso a paso a continuación: =>

  1. Ve a tu pom.xml
  2. Buscar <artifactId>maven-surefire-plugin</artifactId>
  3. Agregue un nuevo <configuration>elemento y luego un <argLine>subelemento en el que pase -Xmx512m -XX:MaxPermSize=256mcomo se muestra a continuación =>

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

Espero que ayude, feliz programación :)

CHAURASIA NIKHIL
fuente