2010-02-16 27 views
57

estoy recibiendo esta excepción en Java:Demasiados archivos abiertos: cuántos están abiertos, lo que son, y cuántos puede la JVM abierta

java.io.FileNotFoundException: (Too many open files) 

Busco las formas de eliminar este problema.

Este error obviamente indica que JVM ha asignado demasiados controladores y el sistema operativo subyacente no permitirá que tenga más. O tengo una fuga en algún lugar con conexiones/secuencias mal cerradas.

Este proceso se ejecuta durante días sin parar y, finalmente, arroja la excepción. Ocurre repetidamente después de 12-14 días de tiempo activo.

¿Cómo luchas contra esto? ¿Hay alguna manera de obtener una lista de identificadores asignados en JVM o hacer un seguimiento cuando alcanza cierta cantidad? Me encantaría que se impriman y ver cómo crece y cuándo. No puedo usar un generador de perfiles porque es un sistema de producción y tengo dificultades para reproducirlo en desarrollo. ¿Cualquier sugerencia?

Estoy monitoreando el tamaño de montón libre y generando una "alarma" cuando se acerca al 1% del total especificado en -Xmx. También sé que si mi número de hilos llega a más de 500, algo definitivamente se va de las manos. Ahora, hay una forma de saber que mi JVM asigna demasiados identificadores del sistema operativo y no los devuelve, p. enchufes, archivos abiertos, etc. Si lo hubiera sabido, sabría dónde buscar y cuándo.

+1

¿Puede dar más información sobre la JVM y el sistema operativo? Además, le sugiero que haga un mayor esfuerzo para reproducir esto en un entorno de desarrollo. Puede ser una molestia, pero cuando tienes ese problema, tratar de "observar e informar" en un sistema de producción probablemente demorará más. – Timothy

+1

Ocurre repetidamente en Linuxes que se ejecutan virtualizados y realmente no tenemos una opción para reproducir esto ejecutando 2 semanas de pruebas cargadas pesadas. Sin embargo, no he visto esto en los cuadros de Windows. Tienes razón, es mejor atraparlo en el desarrollo, pero también me gustaría tener alguna capacidad integrada en el servidor para autocontrol para el futuro. – Dima

+1

RE su edición. No creo que la JVM pueda decirle cómo se abrió ningún archivo. Esa podría ser una buena característica para Sun, pero hasta entonces deberá usar un proceso externo para contarle. Si realmente lo necesita dentro de la JVM escriba un código que ejecute lsof y devuelva el resultado. Además, se puede modificar el límite de archivos abiertos. Por ejemplo, en Linux puede modificar el archivo /etc/security/limits.conf. – bramp

Respuesta

27

Usted no dijo qué sistema operativo se está ejecutando, pero si está ejecutando en Linux se puede utilizar el comando lsof

lsof -p <pid of jvm> 

que listará todos los archivos abiertos por la JVM. O si está ejecutando en Windows puede Process Explorer que mostrará todos los archivos abiertos para todos los procesos.

Al hacer esto, esperamos que pueda restringir qué parte del código mantiene los archivos abiertos.

+0

Buena idea. Compruebe las banderas que puede pasar a 'lsof' para repetir cada X segundos. – Timothy

+0

He agregado el comentario sobre Linixes. ¡Gracias por la sugerencia de lsof! – Dima

+2

Me interesaría saber si mi solución lo ayudó a rastrear el problema. Además, si no es confidencial o demasiado complicado, ¿podría explicarnos qué causó el problema al final? – bramp

23

Dado que está en Linux, le sugiero que compruebe el/proc-Filesystem. Dentro del proceso, encontrará una carpeta con el PID de su proceso que contiene una carpeta llamada 'fd'. Si el identificador de proceso es 1234, el camino es ser

/proc/1234/fd 

Dentro de esa carpeta, encontrará enlaces a todos los archivos abiertos (hacer un 'ls -l'). Por lo general, puede decir por el nombre de archivo qué biblioteca/código puede abrir y no cerrar el archivo.

+0

Gracias, esto es útil, pero lo que busco es algo que evitará profundizar en un sistema de archivos o sistema operativo. Quiero que el proceso de JVM me diga por qué está "enfermo", la razón por la que quiero es ahorrarle a los usuarios el dolor de cabeza si algo sale mal. – Dima

10

Usted puede cambiar el límite de archivos abiertos por añadir lo siguiente a /etc/security/limits.conf:

* soft nofile 2048 # Set the limit according to your needs 
* hard nofile 2048 

A continuación, puede volver a cargar la configuración mediante sysctl -p en la cáscara. Compruebe this article.

simplemente para la corrección puede verificar cuál es el límite actual para los archivos abiertos utilizando: ulimit -n

10

Por lo tanto, la respuesta completa (que combinan respuestas de @phisch y @bramp). Si desea verificar todos los procesos, debe usar sudo. También es bueno guardar el resultado en el archivo - lsof no es barato + este archivo podría ser útil para futuras investigaciones.

sudo lsof > lsof.log 

Mostrar malos:

cat lsof.log | awk '{ print $2 " " $1; }' | sort -rn | uniq -c | sort -rn | head -5 

    2687 114970 java 
    131 127992 nginx 
    109 128005 nginx 
    105 127994 nginx 
    103 128019 nginx 

Guardar lista de descriptores de archivo a archivo, así:

sudo ls -l /proc/114970/fd > fd.log 

Mostrar las de los archivos abiertos:

cat fd | awk '{ print $11 }' | sort -rn | uniq -c | sort -rn | head -n20 
+2

Muchas gracias, realmente útil! Sin embargo, creo que olvidó una pieza en el tercer comando: debería ser 'sudo ls -l/proc/114970/fd> fd.log' – ocramot

+0

@ocramot, ¡de nada! PD. tenías razón, arreglé mi respuesta. – Jimilian

Cuestiones relacionadas