www streams que píldoras pildorasinformaticas pildoras manipulacion informáticas gestor desde crear como cero archivos java jvm cpu-usage infinite-loop

streams - youtube pildoras java



Uso infinito de la CPU al 100% en java.io.FileInputStream.readBytes(Método nativo) (1)

Ahora mismo estoy depurando un programa que tiene dos subprocesos por un proceso externo, y esos dos subprocesos siguen leyendo Process.getErrorStream () y Process.getInputStream () usando un while ((i = in.read(buf, 0, buf.length)) >= 0) loop.

A veces, cuando el proceso externo se bloquea debido a un bloqueo de la JVM (consulte estos archivos hs_err_pid.log ), esos hilos que leen el stdout / stderr de ese proceso externo comienzan a consumir el 100% de la CPU y nunca salen. El cuerpo del bucle no se está ejecutando (he agregado una declaració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 está here y se usa así . Vea esos enlaces para el código completo - aquí están los bits 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 huellas de la pila parecen

"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 procesos de Sysinternals pude obtener trazas nativas de esos subprocesos. La mayoría de las veces, más del 80% del tiempo, el seguimiento de la pila se ve así:

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 está ejecutando 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 una solución?


Todavía no he podido reproducir esto localmente, pero las dos posibles soluciones pueden ser

  • Juega un poco con in.available() .

  • Redirigir stout y stderr en el proceso externo a un socket y leer esto desde el proceso de control en su lugar.