9 causas y soluciones comunes de OOM

Este artículo se reproduce: https://blog.csdn.net/windforce828/article/details/104819055

¿Qué es OOM ? 

OOM, el nombre completo de "Memoria insuficiente", traducido al chino significa "memoria insuficiente", derivado de java.lang.OutOfMemoryError. Eche un vistazo a la descripción oficial: Se lanza cuando la máquina virtual Java no puede asignar un objeto porque no tiene memoria y el recolector de basura no puede dejar más memoria disponible. Significa que cuando la JVM no tiene suficiente memoria para Cuando el objeto asigna espacio y el recolector de basura no tiene espacio para reclamar, se lanzará este error (nota: no es una excepción, porque este problema es lo suficientemente grave como para ser procesado por la aplicación).

¿Por qué OOM?

¿Por qué no hay memoria? Hay dos razones:

1) Menos asignada: por ejemplo, la memoria disponible para la propia máquina virtual (normalmente especificada por el parámetro VM al inicio) es demasiado pequeña.

2) La aplicación usa demasiado y no se libera cuando se agota, lo que se desperdicia. Esto provocará pérdidas de memoria o desbordamiento de la memoria.

Fuga de memoria : La memoria que usa la aplicación no se libera, lo que hace que la máquina virtual no vuelva a usar la memoria. En este momento, esta memoria se pierde porque el solicitante no la usa y la máquina virtual no puede asignarla a otras.

Desbordamiento de memoria : la memoria solicitada excede el tamaño de memoria que la JVM puede proporcionar, y esto se denomina desbordamiento.

En los días en que no había recolección de basura automática, como el lenguaje C y el lenguaje C ++, debemos encargarnos personalmente de la aplicación de memoria y las operaciones de liberación. Si solicitamos memoria, nos olvidamos de liberarla después de usarla. Por ejemplo, nuevo en C ++ pero no eliminación Entonces puede causar pérdidas de memoria. Las pérdidas de memoria ocasionales pueden no causar problemas, mientras que una gran cantidad de pérdidas de memoria pueden provocar un desbordamiento de la memoria.

En el lenguaje Java, debido a la existencia de un mecanismo automático de recolección de basura, generalmente no necesitamos liberar activamente la memoria ocupada por objetos no utilizados, es decir, teóricamente, no habrá "pérdida de memoria". Sin embargo, si la codificación es incorrecta, por ejemplo, la referencia de un objeto se coloca en el Mapa global, aunque el método haya terminado, el recolector de basura reclamará la memoria de acuerdo con la referencia del objeto, de modo que el objeto no se pueda reclamar a tiempo. Si esta situación ocurre demasiadas veces, provocará un desbordamiento de la memoria, como el mecanismo de almacenamiento en caché que se usa a menudo en el sistema. Las pérdidas de memoria en Java, que son diferentes de olvidar eliminar en C ++, a menudo son causadas por pérdidas lógicas.

Cuando la memoria de la JVM es muy insuficiente, se lanzará un java.lang.OutOfMemoryError. Este artículo resume las causas comunes de OOM y sus soluciones, como se muestra en la siguiente figura.

1. Espacio de pila de Java
Cuando la memoria de pila (Heap Space) no tiene suficiente espacio para almacenar el objeto recién creado, arrojará java.lang.OutOfMemoryError: Javaheap space error (según la experiencia de producción real, puede configurar la clave para OutOfMemoryError en el registro del programa Advertencia de palabra, una vez encontrada, trátela inmediatamente).

Análisis de causas
Las causas comunes de los errores de espacio Javaheap se pueden dividir en las siguientes categorías:

Solicitud para crear un objeto muy grande, generalmente una gran matriz.
La cantidad de visitas / datos que superan las expectativas generalmente se debe a un aumento en el tráfico de solicitudes del sistema ascendente, que es común en varias actividades promocionales / seckill. Puede verificar si hay un pico agudo en combinación con los indicadores de tráfico comercial.
Uso excesivo del finalizador (Finalizador), el objeto no es inmediatamente GC.
Pérdida de memoria (Memory Leak), una gran cantidad de referencias de objetos no se liberan, JVM no puede recuperarlas automáticamente, es común en el uso de archivos y otros recursos no se recuperan.
solución

En la mayoría de los casos, normalmente solo necesita aumentar el espacio de memoria del montón de JVM con el parámetro -Xmx. Si aún no se resuelve, puede consultar las siguientes situaciones para su posterior procesamiento:

Si se trata de un objeto muy grande, puede comprobar su racionalidad, por ejemplo, si ha consultado todos los resultados de la base de datos a la vez sin restringir el número de resultados.
Si es la presión máxima de la empresa, considere agregar recursos de la máquina o reducir el límite actual.
Si se trata de una pérdida de memoria, debe encontrar el objeto retenido y modificar el diseño del código, como cerrar la conexión no publicada.
2. Límite de sobrecarga de GC excedido
Cuando el proceso de Java pasa más del 98% del tiempo para realizar GC, pero solo recupera menos del 2% de la memoria, y esta acción se repite 5 veces seguidas, java.lang.OutOfMemoryError: Se lanzará sobrecarga de GC límite excedido error. En pocas palabras, la aplicación básicamente ha agotado toda la memoria disponible y el GC no puede recuperarla.

La causa y la solución de este tipo de problema son muy similares al espacio Javaheap, puede consultar lo anterior.

3. Espacio de Permgen
Este error indica que la Generación Permanente está llena, generalmente porque el número de clases cargadas es demasiado grande o el tamaño es demasiado grande.

Análisis de causa

Los objetos de almacenamiento de generación permanente incluyen principalmente las siguientes categorías:

La definición de clase cargada / almacenada en caché en la memoria, incluido el nombre, campo, método y código de bytes de la clase; el
grupo constante;
la clase asociada con la matriz de objetos / matriz de tipos;
la información de clase optimizada por el compilador JIT.
El uso de PermGen está relacionado positivamente con el número / tamaño de clases cargadas en la memoria.

solución

Según el momento del informe de errores de Permgen Space, se pueden utilizar diferentes soluciones, como se muestra a continuación:

Se informa de un error cuando se inicia el programa, modificar el parámetro de inicio -XX: MaxPermSize y aumentar el espacio de generación permanente.
Se informa de un error cuando se vuelve a implementar la aplicación. Es muy probable que ninguna aplicación no se haya reiniciado, lo que provoca que se carguen varias copias de la información de la clase. Simplemente reinicie la JVM para solucionarlo.
Se informa un error durante el tiempo de ejecución, y la aplicación puede crear dinámicamente una gran cantidad de clases, y el ciclo de vida de estas clases es muy corto, pero la JVM no descargará las clases de forma predeterminada. Puede configurar los dos parámetros -XX: + CMSClassUnloadingEnabled y -XX: + UseConcMarkSweepGC para permitir la desinstalación de JVM clase.
Si el método anterior no se puede resolver, puede usar el comando jmap para volcar el objeto de memoria jmap-dump: format = b, file = dump.hprof, y luego usar la función Eclipse MAT https://www.eclipse.org/mat para analizar el cargador de clases más caro y Repite la clase.

4. Metaspace
JDK 1.8 usa Metaspace para reemplazar la Generación Permanente Este error significa que Metaspace está lleno, generalmente porque el número de clases cargadas es demasiado grande o el tamaño es demasiado grande.

Las causas y soluciones para tales problemas son muy similares a Permgenspace, puede consultar lo anterior. Es importante tener en cuenta que el parámetro de inicio para ajustar el tamaño del espacio de Metaspace es -XX: MaxMetaspaceSize.

5. No se puede crear un nuevo subproceso nativo
Cada subproceso de Java necesita ocupar una cierta cantidad de espacio de memoria Cuando la JVM solicita al sistema operativo subyacente que cree un nuevo subproceso nativo, se informará de dicho error si no hay suficiente asignación de recursos.

Análisis de causa

Cuando JVM no solicita al sistema operativo que cree un subproceso nativo, arrojará No se puede crear un subproceso negativo. Los motivos comunes incluyen lo siguiente:

El número de subprocesos excede el límite ulimit del número máximo de subprocesos del sistema operativo; el
número de subprocesos excede kernel.pid_max (solo reiniciar); la
memoria nativa es insuficiente;
el proceso común de este problema incluye principalmente los siguientes pasos:

La aplicación dentro de la JVM solicita crear un nuevo subproceso de Java; el
método nativo de la JVM delega la solicitud y solicita al sistema operativo que cree un subproceso nativo; el
sistema operativo intenta crear un nuevo subproceso nativo y le asigna memoria;
si la operación La memoria virtual del sistema se ha agotado o está restringida por el espacio de direcciones del proceso de 32 bits, el sistema operativo rechazará esta asignación de memoria nativa; la
JVM arrojará java.lang.OutOfMemoryError: Unableto createnewnativethread error.
solución

Actualice la configuración para proporcionar más memoria para la máquina;
reduzca el tamaño del Java Heap Space;
solucione el problema de fuga de subprocesos de la aplicación;
limite el tamaño del grupo de subprocesos;
use el parámetro -Xss para reducir el tamaño de la pila de subprocesos;
aumente el número máximo de subprocesos a nivel del sistema operativo: ejecutar ulimia-a Vea el límite máximo de subprocesos y use ulimit-u xxx para ajustar el límite máximo de subprocesos.
ulimit -a ... Omitir parte del contenido ... max procesos de usuario (-u) 16384

6. ¿Sin espacio de intercambio?
Este error indica que se ha agotado toda la memoria virtual disponible. La memoria virtual consta de dos partes: memoria física y espacio de intercambio. Cuando la memoria virtual solicitada por el programa en tiempo de ejecución se desborda, se informará un error ¿Fuera de espacio de intercambio?

Análisis de causa

Los motivos habituales de este error incluyen las siguientes categorías:

Espacio de direcciones insuficiente;
se ha agotado la memoria física;
fuga nativa de la aplicación, como la aplicación continua de memoria local, pero no la liberación.
Ejecute el comando jmap-histo: live para forzar la ejecución de Full GC; si la memoria cae significativamente después de varias ejecuciones, básicamente se confirma como un problema de Direct ByteBuffer.
solución

Se pueden tomar las siguientes soluciones según la causa del error:

Actualice el espacio de direcciones a 64 bits;
use Arthas para verificar si se trata de un problema de descompresión de Inflater / Deflater y, de ser así, llame al método end explícitamente.
Para problemas de Direct ByteBuffer, el umbral se puede reducir mediante el parámetro de inicio -XX: MaxDirectMemorySize.
Actualice la configuración del servidor / aísle la implementación para evitar conflictos.
7. Matar el proceso o sacrificar al hijo
Hay un trabajo del núcleo (Trabajo del núcleo) llamado Out of Memory Killer, que "mata" ciertos procesos cuando la memoria disponible es extremadamente baja. OOM Killer puntuará todos los procesos y luego "matará" los procesos con puntuaciones más bajas. Para conocer las reglas de puntuación específicas, consulte Sobrevivir al asesino OOM de Linux.

A diferencia de otros errores de OOM, el error secundario de Killprocessorsacrifice no se activa por el nivel de JVM, sino por el nivel del sistema operativo.

Análisis de causa

Por defecto, el kernel de Linux permite que la cantidad total de memoria solicitada por el proceso sea mayor que la memoria disponible del sistema, y ​​este método de "multiplexación cambiante" puede hacer un uso más efectivo de los recursos del sistema.

Sin embargo, este enfoque traerá inevitablemente ciertos riesgos de "sobreventa". Por ejemplo, algunos procesos continúan ocupando la memoria del sistema y luego otros procesos no tienen memoria disponible. En este punto, el sistema activará automáticamente OOM Killer, buscará procesos con puntuaciones bajas y los "matará" para liberar recursos de memoria.

solución

Actualice la configuración del servidor / aísle la implementación para evitar conflictos.
Afinación OOM Killer.
8. El tamaño de la matriz solicitado excede el límite de VM
JVM limita la longitud máxima de la matriz Este error indica que la matriz solicitada por el programa excede el límite de longitud máxima.

Antes de asignar memoria para la matriz, la JVM verifica si la estructura de datos que se asignará es direccionable en el sistema, generalmente Integer.MAX_VALUE-2.

Este tipo de problema es relativamente raro y, por lo general, es necesario verificar el código para confirmar si la empresa necesita crear una matriz tan grande y si se puede dividir en varios bloques y ejecutar en lotes.

9. La memoria de búfer directa
ava permite que las aplicaciones accedan directamente a la memoria fuera del montón a través de Direct ByteBuffer Muchos programas de alto rendimiento implementan E / S de alta velocidad a través de Direct ByteBuffer combinado con Memory Mapped File.

Análisis de causa

El tamaño predeterminado de Direct ByteBuffer es 64 MB. Una vez que se excede el límite, se producirá un error de memoria Directbuffer.

solución

Java solo puede usar Direct ByteBuffer a través del método ByteBuffer.allocateDirect. Por lo tanto, este método puede ser interceptado por herramientas de diagnóstico en línea como Arthas para solucionar problemas.
Compruebe si NIO se utiliza directa o indirectamente, como netty, jetty, etc.
Ajuste el límite superior de Direct ByteBuffer mediante el parámetro de inicio -XX: MaxDirectMemorySize.
Verifique si el parámetro JVM tiene la opción -XX: + DisableExplicitGC, si la hay, elimínela, porque este parámetro invalidará System.gc ().
Verifique el código de uso de memoria fuera del montón para confirmar si hay una pérdida de memoria; o llame al método clean () de sun.misc.Cleaner a través de la reflexión para liberar activamente el espacio de memoria que tiene Direct ByteBuffer.
De hecho, la capacidad de memoria es insuficiente, actualice la configuración.
 

 

Supongo que te gusta

Origin blog.csdn.net/LOVE_Me__/article/details/107601841
Recomendado
Clasificación