2012-05-04 19 views
17

He revisado las otras preguntas similares en SO, pero parecen ser causadas por otros problemas.JDK 1.7: "Demasiados archivos abiertos" debido a semáforos POSIX?

Primero me aseguré de cerrar juiciosamente todos mis identificadores de archivo, y luego usé lsof -p <pid of java> para ver mi lista de archivos.

Se mantiene bastante constante a lo largo de mi tiempo de ejecución, pero luego periódicamente voy a tener unos 10.000 indicaciones que figuran en lsof como esto:

COMMAND PID USER FD  TYPE DEVICE SIZE/OFF  NODE NAME 
             ... 
java 36809 smm *235r PSXSEM    0t0   kcms00008FC901624000 
java 36809 smm *236r PSXSEM    0t0   kcms00008FC901624000 
java 36809 smm *237r PSXSEM    0t0   kcms00008FC901624000 
java 36809 smm *238r PSXSEM    0t0   kcms00008FC901624000 
java 36809 smm *239r PSXSEM    0t0   kcms00008FC901624000 

La página del manual dice PSXSEM tipo es un semáforo POSIX. ¿Alguna pista para qué JDK usa los semáforos POSIX? Por cierto, la aplicación es una aplicación de línea de comando de un solo hilo en este momento.

fondo potencialmente útiles: Primero me di cuenta esto después de actualizar a JDK 1.7 en Mac OS X 10.7.3:

java version "1.7.0_04" 
Java(TM) SE Runtime Environment (build 1.7.0_04-b21) 
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode) 

Actualización: repointing $JAVA_HOME en JDK 1.6 Parece que hay una solución para el problema.

java version "1.6.0_31" 
Java(TM) SE Runtime Environment (build 1.6.0_31-b04-415-11M3635) 
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01-415, mixed mode) 

¿Qué es JDK 1.7 doing differently?

+0

Probaría un generador de perfiles de Java normal, como YourTrack o incluso solo VisualVM para ver si se puede correlacionar la creación de los semáforos 10K con la creación de un gran número de objetos de la biblioteca de Java. –

+2

Todavía veo este problema, pero no estoy usando ImageIO (al menos no directamente). Las reparaciones solo hacen que aumente el número de semáforos, hasta que obtengo un: 2012-05-09 16: 30: 12.856 java [14407: 3d87] La ​​interfaz de usuario persistente no puede abrir el archivo de archivo: // localhost/Users/juancn/Library /Saved%20Application%20State/net.java.openjdk.cmd.savedState/window_1.data: Demasiados archivos abiertos (24) – juancn

Respuesta

7

que era capaz de rastrear a este bloque de código:

BufferedImage image = null; 
ImageInputStream stream = null; 
try { 
    stream = new FileImageInputStream(file); 
    image = ImageIO.read(stream); 

} catch (Exception ex) { 
    log.error("Image could not be read: "+file.getPath()); 

} finally { 
    // ImageIO closes input stream unless null is returned 
    // http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(javax.imageio.stream.ImageInputStream) 
    if (stream != null && image == null) { 
     try { 
      stream.close(); 
     } catch (IOException ex) { 
      log.error("ERROR closing image input stream: "+ex.getMessage(), ex); 
     } 
    } 
} 

Los JavaDocs dicen específicamente que este método (a diferencia de los otros) se cierra automáticamente la corriente. De hecho, cuando intentas cerrarlo manualmente, arroja una excepción que dice 'cerrado'. Estaba usando esta sobrecarga ya que el otro dice que lo envuelve en un ImageInputStream de todos modos, así que pensé que podría ahorrar algo de trabajo.

Cambio del bloque de utilizar un normal FileInputStream correcciones de la fuga:

BufferedImage image = null; 
InputStream stream = null; 
try { 
    stream = new FileInputStream(file); 
    image = ImageIO.read(stream); 

} catch (Exception ex) { 
    log.error("Image could not be read: "+file); 

} finally { 
    if (stream != null) { 
     try { 
      stream.close(); 
     } catch (IOException ex) { 
      log.error("ERROR closing image input stream: "+ex.getMessage(), ex); 
     } 
    } 
} 

Esto me parece un error en JDK 1.7 como 1.6 funcionó bien aquí.

Actualización: Acabo de llamar submitted a bug report a Oracle por este problema.

+0

desafortunadamente no parece estar solucionado a partir del 1.7.0_04, es una lástima, aunque no hay otro API en la especificación que le permiten verificar la validez de una imagen. Sin embargo, supongo que tienes suerte, todavía estoy consiguiendo que esos semáforos sigan matando al contenedor JEE. –

+0

@ArchimedesTrajano Todavía he tenido problemas intermitentes incluso con este trabajo, también. Parece ser un error bastante malo. – mckamey

+0

Está solo en archivos JPEG. Como solo uso para verificar si un archivo JPEG es "válido", solo compruebo si tiene el inicio de la imagen y el final de la imagen en los lugares adecuados. –

4

Encontré otra causa. Parece que el método toRGB() de ColorSpace está filtrando semáforos. Ejecutar el siguiente código:

import java.awt.color.ColorSpace; 
public class Test 
{ 
    public static void main(String[] args) throws Throwable { 
     final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); 
     for(int i = 0; i < 10000000; i++) { 
      CIEXYZ.toRGB(new float[] {80f, 100, 100}); 
     } 
    } 
} 

Con:

java version "1.7.0_04" 
Java(TM) SE Runtime Environment (build 1.7.0_04-b21) 
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode) 

que dejará fuera de los archivos del sistema.

EDIT: ya presentó un bug report a Oracle

+0

Buen hallazgo. Gracias. – mckamey

4

Actualización: Como otros usuarios han dicho, ImageIO estaba goteando semáforos en 1.7.0_04 y 1.7.0_05. Los informes de errores del usuario juancn y el usuario mckamey han sido marcados como fijos y cerrados (¡gracias chicos!).La explicación:

Esta revisión informa sobre una pérdida de manejadores de archivos en macosx. Mencionó dos formas de manejar fugas: a través de ImageIO.read (ImageInputStream) y vía semáforos.

No observo la primera filtración: cerramos explícitamente el flujo de entrada si encontramos un lector apropiado, y esto es suficiente (al menos en 1.7.4) para liberar los identificadores de archivo.

Sin embargo, en el caso de los semáforos que se escapan de toneladas de mangos: llevamos a cabo la conversión de color para cada línea de imagen jpeg, y cada vez que creamos un semáforo (porque vemos 2 o más CPU instalado en el sistema), luego reducimos el número de tareas por separado a 1 (porque tenemos una sola línea de escaneo para procesar) y debido a esto nunca desenlazamos el semáforo.

El mismo problema está presente en los sistemas Linux, pero en menor grado porque ocupamos un solo identificador de archivo por semáforo con nombre, mientras que en macosx siempre ocupamos un nuevo identificador de archivo.

solución sugerida simplemente pospone la creación del llamado semáforo hasta que se esclarezca el número de tareas separadas, por lo que, ahora no creamos semáforos para la lectura de imágenes y color sencilla conversiones (como ColorSpace.toRGB()). Además de esto, ahora usamos el puntero pSem como disparador para la destrucción del semáforo.

A pesar de que sus informes indican que la solución está en la versión 8, un informe backport indica que fue fixed in 1.7.0_06.

Así que si estás viendo esto en 1.7.0_04 o 05, la actualización de al menos 1,7 .0_06 se encargará de este problema.

Cuestiones relacionadas