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.