2012-04-16 10 views
22

Ahora estoy depurando un programa que tiene dos hilos por proceso externo, y esos dos hilos continúan leyendo Process.getErrorStream() y Process.getInputStream() utilizando un bucle while ((i = in.read(buf, 0, buf.length)) >= 0).Infinite 100% uso de CPU en java.io.FileInputStream.readBytes (Método nativo)

A veces, cuando el proceso externo se bloquea debido a un bloqueo de JVM (consulte these hs_err_pid.log files), los hilos que leen stdout/stderr de ese proceso externo comienzan a consumir 100% de CPU y nunca salen. El cuerpo del bucle no se está ejecutando (he agregado una instrucción de registro allí), por lo que el bucle infinito parece estar dentro del método nativo java.io.FileInputStream.readBytes.

He reproducido esto tanto en Windows 7 de 64 bits (jdk1.6.0_30 de 64 bits, jdk1.7.0_03 de 64 bits), como en Linux 2.6.18 (jdk1.6.0_21 de 32 bits). El código en cuestión es here y se usa like this. Ver los enlaces para el código completo - aquí están las cosas interesantes:

private final byte[]    buf = new byte[256]; 
private final InputStream   in; 
...  

int i; 
while ((i = this.in.read(this.buf, 0, this.buf.length)) >= 0) { 
    ... 
} 

Las trazas de la pila se ven como

"PIT Stream Monitor" daemon prio=6 tid=0x0000000008869800 nid=0x1f70 runnable [0x000000000d7ff000] 
    java.lang.Thread.State: RUNNABLE 
    at java.io.FileInputStream.readBytes(Native Method) 
    at java.io.FileInputStream.read(FileInputStream.java:220) 
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:218) 
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:258) 
    at java.io.BufferedInputStream.read(BufferedInputStream.java:317) 
    - locked <0x00000007c89d6d90> (a java.io.BufferedInputStream) 
    at org.pitest.util.StreamMonitor.readFromStream(StreamMonitor.java:38) 
    at org.pitest.util.StreamMonitor.process(StreamMonitor.java:32) 
    at org.pitest.util.AbstractMonitor.run(AbstractMonitor.java:19) 
    Locked ownable synchronizers: 
    - None 

o

"PIT Stream Monitor" daemon prio=6 tid=0x0000000008873000 nid=0x1cb8 runnable [0x000000000e3ff000] 
    java.lang.Thread.State: RUNNABLE 
    at java.io.FileInputStream.readBytes(Native Method) 
    at java.io.FileInputStream.read(FileInputStream.java:220) 
    at org.pitest.util.StreamMonitor.readFromStream(StreamMonitor.java:38) 
    at org.pitest.util.StreamMonitor.process(StreamMonitor.java:32) 
    at org.pitest.util.AbstractMonitor.run(AbstractMonitor.java:19) 
    Locked ownable synchronizers: 
    - None 

Con el Explorador de Sysinternals Proceso pude obtener rastros de pila nativos de esos hilos. Muy a menudo, más del 80% de las veces, el seguimiento de pila es el siguiente:

ntdll.dll!NtReadFile+0xa 
KERNELBASE.dll!ReadFile+0x7a 
kernel32.dll!ReadFile+0x59 
java.dll!handleRead+0x2c 
java.dll!VerifyClassCodesForMajorVersion+0x1d1 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

Esto también sucede con bastante frecuencia:

ntdll.dll!RtlNtStatusToDosErrorNoTeb+0x52 
ntdll.dll!RtlNtStatusToDosError+0x23 
KERNELBASE.dll!GetCurrentThreadId+0x2c 
KERNELBASE.dll!CreatePipe+0x21a 
kernel32.dll!ReadFile+0x59 
java.dll!handleRead+0x2c 
java.dll!VerifyClassCodesForMajorVersion+0x1d1 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

ntdll.dll!RtlNtStatusToDosErrorNoTeb+0x42 
ntdll.dll!RtlNtStatusToDosError+0x23 
KERNELBASE.dll!GetCurrentThreadId+0x2c 
KERNELBASE.dll!CreatePipe+0x21a 
kernel32.dll!ReadFile+0x59 
java.dll!handleRead+0x2c 
java.dll!VerifyClassCodesForMajorVersion+0x1d1 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

Y a veces es la ejecución de esta parte del código:

java.dll!VerifyClassCodesForMajorVersion+0xc3 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

java.dll!Java_sun_io_Win32ErrorMode_setErrorMode+0x847c 
java.dll!VerifyClassCodesForMajorVersion+0xd7 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

jvm.dll!JNI_GetCreatedJavaVMs+0x1829f 
java.dll!VerifyClassCodesForMajorVersion+0x128 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

jvm.dll+0x88c1 
jvm.dll!JNI_GetCreatedJavaVMs+0x182a7 
java.dll!VerifyClassCodesForMajorVersion+0x128 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

java.dll!VerifyClassCodesForMajorVersion+0x10b 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

jvm.dll!JNI_CreateJavaVM+0x1423 
java.dll!VerifyClassCodesForMajorVersion+0x190 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

jvm.dll+0x88bf 
jvm.dll!JNI_CreateJavaVM+0x147d 
java.dll!VerifyClassCodesForMajorVersion+0x190 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

java.dll!VerifyClassCodesForMajorVersion+0x1aa 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

java.dll!VerifyClassCodesForMajorVersion+0x1c3 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

java.dll!VerifyClassCodesForMajorVersion+0x224 
java.dll!Java_java_io_FileInputStream_readBytes+0x1d 

¿Alguna idea de cómo resolver este problema? ¿Es este un problema conocido con la JVM? ¿Hay alguna solución?

+3

¿Podría incluir su código de bucle? Por cierto, la condición '> = 0' es demasiado amplia, si' buf.length' no es cero, entonces read() garantiza que leerá al menos 1 byte o devolverá -1 (o arrojará una excepción). –

+0

¿Qué? ¿'Process.getInputStream()' devuelve un FileInputStream? –

+0

Sí. En java.lang.ProcessImpl # ProcessImpl, puede ver que stdout_stream y stderr_stream se inicializan con FileInputStream. Tiene sentido desde el punto de vista de Unix, donde todo es un archivo. –

Respuesta

1

todavía no he sido capaz de reproducir este local, pero las dos soluciones posibles podría ser

  • jugar con in.available().

  • redirección stout y stderr en el proceso externo a una toma de corriente y leen esto desde el proceso de control en su lugar.

+0

[Una solución rápida usando in.available()] (http://code.google.com/p/pitestrunner/source/browse/pitest/src/main/java/org/pitest/util/StreamMonitor.java?spec = svn0607ac947dd76768f5e852350386bc9c324a6005 & r = 0607ac947dd76768f5e852350386bc9c324a6005 # 59) ha ayudado a evitar el problema por el momento. Todavía estamos buscando una mejor solución y la razón por la que esto está sucediendo en primer lugar. Trataré de producir un [SSCCE] (http://sscce.org/) eliminando el código superfluo del proyecto de fuente cerrada donde puedo reproducir esto. –

+0

El problema se puede volver a producir al bloquear el proceso secundario con el bucle de asignación de matriz infinita de http://stackoverflow.com/questions/65200/how-do-you-crash-a-jvm y probablemente las otras técnicas enumeradas allí . – henry

Cuestiones relacionadas