"Java.lang.OutOfMemoryError: no se puede crear un nuevo hilo nativo"

124

Estamos obteniendo "java.lang.OutOfMemoryError : unable to create new native Thread"en 8GB RAM VM después de 32k subprocesos (ps -eLF | grep -c java)

Sin embargo, "top" and "free -m" shows 50% free memory available. JDk es de 64 bits y se probó con HotSpot y JRockit. El servidor tiene Linux 2.6.18

También probamos los OS stack size (ulimit -s)límites de ajuste y proceso máximo (ulimit -u), aumento de limit.conf pero todo en vano.

También probamos casi todas las combinaciones posibles de tamaño de almacenamiento dinámico, manteniéndolo bajo, alto, etc.

El script que usamos para ejecutar la aplicación es

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

Gracias por la respuesta.

Hemos intentado editar /etc/security/limits.conf y ulimit pero aún así

[root@jboss02 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 72192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 72192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
Deepak Tewani
fuente
11
Los sistemas operativos tienen límites en la cantidad de subprocesos que puede crear. ¿Por qué estás creando más de 32k hilos? Es muy probable que su sistema no tenga miles de núcleos de procesador, por lo que crear tantos subprocesos no es útil. Utilice un grupo de subprocesos ( ExecutorService) en su lugar.
Jesper
Gracias por la respuesta. Estamos usando una biblioteca de código abierto y estamos intentando cargar eso. Cualquier biblioteca de código abierto está creando tantos subprocesos. Pero lo que no entiendo es cuando "top" muestra un 50% de memoria libre, entonces por qué OutOfMemory Error.
Deepak Tewani
La biblioteca de código abierto que estamos usando en la Biblioteca ICE4j
Deepak Tewani
11
OutOfMemoryError no significa necesariamente que se haya agotado el espacio de almacenamiento dinámico o RAM "general". En este caso, está claro que la falla se debió a que el sistema operativo no tenía los recursos para asignar un subproceso adicional. Tener un 50% de memoria libre es irrelevante para esta falla en particular.
Andrzej Doyle
1
¿Cuáles son los otros recursos necesarios para crear nuevos hilos? Teníamos la impresión de que si aumentamos la RAM, podríamos crear más hilos.
Guíanos

Respuestas:

80

Esto no es un problema de memoria, aunque el nombre de la excepción lo sugiere, sino un problema de recursos del sistema operativo. Se está quedando sin subprocesos nativos, es decir, cuántos subprocesos permitirá el sistema operativo utilizar su JVM.

Este es un problema poco común, porque rara vez se necesitan tantos. ¿Tiene una gran cantidad de subprocesos incondicionales donde los subprocesos deberían terminar pero no terminan?

Puede considerar reescribir el uso de Callable / Runnables bajo el control de un Ejecutor si es posible. Hay muchos ejecutores estándar con varios comportamientos que su código puede controlar fácilmente.

(Hay muchas razones por las cuales el número de subprocesos es limitado, pero varían de un sistema operativo a otro)

Thorbjørn Ravn Andersen
fuente
Gracias por la respuesta. Estamos usando una biblioteca de código abierto ICE4j y estamos intentando cargar eso. No podemos aumentar el límite de subprocesos en el sistema operativo cuando sabemos que queda un 50% de memoria en el servidor.
Deepak Tewani
Posiblemente, pero creo que no te ayudará como tal. Si se quedan sin recursos cuando se realizan pruebas de carga, debe poder controlar lo que sucede en su aplicación. ¿Por qué tiene 32000 hilos activos a la vez?
Thorbjørn Ravn Andersen
Estamos creando clientes de 11K que usan subprocesos de 32 K para leer, escribir datos en sockets UDP. De estos subprocesos de 32 K, los subprocesos de 10K son hilos vivos que se utilizan para mantener el socket abierto
Deepak Tewani
Creo que este problema se resuelve en los servidores web modernos. Además, udp puede perder paquetes: ¿hay alguna razón por la que no solo usa un servidor web?
Thorbjørn Ravn Andersen
77
Porque la excepción OutOfMemory debería haberse llamado OutOfResources. El sistema operativo no puede proporcionar el recurso que necesita. (Y resultó que no conocía ice4j)
Thorbjørn Ravn Andersen
14

Encontré el mismo problema durante la prueba de carga, la razón es porque JVM no puede crear un nuevo hilo Java. A continuación se muestra el código fuente de JVM

if (native_thread->osthread() == NULL) {    
// No one should hold a reference to the 'native_thread'.    
    delete native_thread;   
if (JvmtiExport::should_post_resource_exhausted()) {      
    JvmtiExport::post_resource_exhausted(        
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | 
        JVMTI_RESOURCE_EXHAUSTED_THREADS, 
        "unable to create new native thread");    
    } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread");  
} Thread::start(native_thread);`

Causa raíz: JVM lanza esta excepción cuando JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (recursos agotados (significa memoria agotada)) o JVMTI_RESOURCE_EXHAUSTED_THREADS (Subprocesos agotados).

En mi caso, Jboss está creando demasiados hilos para atender la solicitud, pero todos los hilos están bloqueados. Debido a esto, JVM también se agota con subprocesos con memoria (cada subproceso contiene memoria, que no se libera, porque cada subproceso está bloqueado).

Analizado los volcados de subprocesos de Java, se observó que casi 61K subprocesos están bloqueados por uno de nuestros métodos, lo que está causando este problema. A continuación se muestra la parte del volcado de subprocesos

"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
   java.lang.Thread.State: BLOCKED (on object monitor)
Madhu Cheepati
fuente
¿Cómo fue el bloqueo del método? ¿Nunca regresas?
Thorbjørn Ravn Andersen
8

Es probable que su sistema operativo no permita la cantidad de subprocesos que está tratando de crear, o está llegando a algún límite en la JVM. Especialmente si se trata de un número tan redondo como 32k, un límite de un tipo u otro es muy probablemente el culpable.

¿Estás seguro de que realmente necesitas 32k hilos? La mayoría de los lenguajes modernos tienen algún tipo de soporte para grupos de subprocesos reutilizables: estoy seguro de que Java también tiene algo en su lugar (como ExecutorService, como mencionó el usuario Jesper). Tal vez podría solicitar subprocesos de dicho grupo, en lugar de crear manualmente nuevos.

Theodoros Chatzigiannakis
fuente
1
Gracias por la respuesta. Estamos usando una biblioteca de código abierto ICE4j y estamos intentando cargar eso. No podemos aumentar el límite de subprocesos en el sistema operativo cuando sabemos que queda un 50% de memoria en el servidor.
Deepak Tewani
1
Estamos creando clientes de 11K que usan subprocesos de 32 K para leer, escribir datos en sockets UDP. De estos subprocesos de 32 K, los subprocesos de 10K son hilos vivos que se utilizan para mantener el socket abierto
Deepak Tewani
7

También recomendaría mirar el Tamaño de la pila de hilos y ver si se crean más hilos. El tamaño de pila de subprocesos predeterminado para JRockit 1.5 / 1.6 es 1 MB para VM de 64 bits en el sistema operativo Linux. Los subprocesos de 32K requerirán una cantidad significativa de memoria física y virtual para cumplir con este requisito.

Intente reducir el tamaño de la pila a 512 KB como punto de partida y vea si ayuda a crear más hilos para su aplicación. También recomiendo explorar la escala horizontal, por ejemplo, dividir el procesamiento de su aplicación en más máquinas físicas o virtuales.

Cuando se utiliza una máquina virtual de 64 bits, el límite real dependerá de la disponibilidad de memoria virtual y física del sistema operativo y de los parámetros de ajuste del sistema operativo, como ulimitc. También recomiendo el siguiente artículo como referencia:

OutOfMemoryError: no se puede crear un nuevo hilo nativo - Problema desmitificado

PH
fuente
5

Si jvm se inicia a través de systemd, puede haber un límite máximo de tareas por proceso (las tareas en realidad significan subprocesos) en algunos sistemas operativos Linux.

Puede verificar esto ejecutando el "estado del servicio" y verificar si hay un límite de maxTasks. Si lo hay, puede eliminarlo editando /etc/systemd/system.conf, agregando una configuración: DefaultTasksMax = infinity

Clement.Xu
fuente
3

Tuve el mismo problema debido a los procesos fantasma que no aparecían al usar top en bash. Esto evitó que la JVM generara más hilos.

Para mí, se resolvió al enumerar todos los procesos de Java con jps (solo ejecutar jpsen su shell) y los eliminó por separado usando elkill -9 pid comando bash para cada proceso fantasma.

Esto podría ayudar en algunos escenarios.

mac7
fuente
2

Tiene la oportunidad de enfrentarlo java.lang.OutOfMemoryError: Unable to create new native threadcada vez que la JVM solicite un nuevo hilo del sistema operativo. Siempre que el sistema operativo subyacente no pueda asignar un nuevo hilo nativo, se lanzará este OutOfMemoryError. El límite exacto para los subprocesos nativos depende mucho de la plataforma, por lo que se recomienda conocer esos límites ejecutando una prueba similar al ejemplo de enlace a continuación. Pero, en general, la situación que causa java.lang.OutOfMemoryError: Unable to create new native threadpasa por las siguientes fases:

  1. Una aplicación que se ejecuta dentro de la JVM solicita un nuevo subproceso Java.
  2. El código nativo de JVM representa la solicitud para crear un nuevo hilo nativo para el sistema operativo El sistema operativo intenta crear un nuevo hilo nativo que requiere que se asigne memoria al hilo
  3. El sistema operativo rechazará la asignación de memoria nativa ya sea porque el tamaño del proceso Java de 32 bits ha agotado su espacio de direcciones de memoria, por ejemplo, se ha alcanzado el límite de tamaño del proceso de (2-4) GB, o porque la memoria virtual del sistema operativo se ha agotado por completo
  4. Se arroja el error java.lang.OutOfMemoryError: no se puede crear un nuevo hilo nativo.

Referencia: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

Sazzad Hissain Khan
fuente
2

Para encontrar qué procesos están creando hilos, intente:

ps huH

Normalmente redirijo la salida a un archivo y analizo el archivo fuera de línea (el recuento de subprocesos para cada proceso es el esperado o no)

usuario8521771
fuente
1

Si su trabajo falla debido a OutOfMemmory en los nodos, puede modificar la cantidad máxima de mapas y reductores y la JVM opta por cada uno. mapred.child.java.opts (el valor predeterminado es 200Xmx) generalmente debe aumentarse en función del hardware específico de sus nodos de datos.

Este enlace puede ser útil ... por favor verifique

Pavan Kumar K
fuente
1
Todos ya hemos intentado ese cambio que se da en ese enlace. Pero el resultado es el mismo :(
Deepak Tewani
1

su configuración de JBoss tiene algunos problemas, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms y Xmx están limitando su uso de memoria JBoss, al valor configurado, por lo que desde los 8 Gb que tiene el servidor solo está usando 512 M + algo extra para su propio propósito, aumente ese número, recuerde dejar algo libre para el sistema operativo y otras cosas que se ejecutan allí y puede hacerlo funcionar a pesar del código desagradable. Arreglar el código también sería bueno, si puedes.

usuario3390284
fuente
1

Este error puede surgir debido a las siguientes dos razones:

  • No hay espacio en la memoria para acomodar nuevos hilos.

  • El número de subprocesos supera el límite del sistema operativo.

Dudo que el número de hilos haya excedido el límite para el proceso de Java

Por lo tanto, es probable que el problema se deba a la memoria. Un punto a considerar es

los hilos no se crean dentro del montón JVM. Se crean fuera del montón JVM. Entonces, si queda menos espacio en la RAM, después de la asignación del montón JVM, la aplicación se ejecutará en "java.lang.OutOfMemoryError: no se puede crear un nuevo hilo nativo".

La posible solución es reducir la memoria de almacenamiento dinámico o aumentar el tamaño general de la memoria RAM

Disidente
fuente
0

Tuve este mismo problema y resultó ser un uso incorrecto de una API de Java. Estaba inicializando un constructor en un método de procesamiento por lotes que se suponía que no debía iniciarse más de una vez.

Básicamente estaba haciendo algo como:

for (batch in batches) {
    process_batch(batch)
}

def process_batch(batch) {
    var client = TransportClient.builder().build()
    client.processList(batch)
}

cuando debería haber hecho esto:

for (batch in batches) {
    var client = TransportClient.builder().build()
    process_batch(batch, client)
}

def process_batch(batch, client) {
    client.processList(batch)
}
anthonybell
fuente
-4

En primer lugar, no culparía tanto al sistema operativo / máquina virtual ... sino al desarrollador que escribió el código que crea tantos hilos . Básicamente, en algún lugar de su código (o tercero) se crean muchos hilos sin control .

Revise cuidadosamente el stacktraces / código y controle el número de hilos que se crean. Normalmente, su aplicación no debería necesitar una gran cantidad de hilos, si lo hace es un problema diferente.

Flueras Bogdan
fuente
10
Esta no es una solución a la pregunta.
ftrujillo