Ich bin gerade im Debuggen eines Programms, das zwei Threads pro einem externen Prozess hat, und diese beiden Threads lesen weiter Process.getErrorStream() und Process.getInputStream() mit einer while ((i = in.read(buf, 0, buf.length)) >= 0)
-Schleife.Infinite 100% CPU-Auslastung bei java.io.FileInputStream.readBytes (Native Methode)
Manchmal, wenn der externe Prozess aufgrund eines JVM-Absturzes abstürzt (siehe these hs_err_pid.log files), beginnen jene Threads, die den stdout/stderr dieses externen Prozesses lesen, 100% CPU zu verbrauchen und niemals zu beenden. Der Schleifenkörper wird nicht ausgeführt (Ich habe eine Protokollierungsanweisung dort hinzugefügt), so scheint die Endlosschleife innerhalb der nativen Methode java.io.FileInputStream.readBytes
zu sein.
Ich habe dies auf Windows 7 64-Bit (jdk1.6.0_30 64-Bit, jdk1.7.0_03 64-Bit) und Linux 2.6.18 (jdk1.6.0_21 32-Bit) reproduziert. Der betreffende Code ist here und wird like this verwendet. Sehen Sie diese Links für den vollständigen Code - hier die interessanten Bits sind:
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) {
...
}
Die Stack-Traces aussehen
"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
oder
"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
Mit dem Sysinternals Process Explorer konnte ich native Stack-Spuren dieser Threads erhalten. Meistens über 80% der Zeit, sieht der Stack-Trace wie folgt aus:
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
Dies geschieht auch oft:
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
und manchmal ist es, diesen Teil des Codes ausführen:
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
Irgendwelche Ideen, wie man dieses Problem löst? Ist das ein bekanntes Problem mit der JVM? Gibt es eine Problemumgehung?
Könnten Sie Ihren Loop-Code einschließen? Übrigens ist die Bedingung '> = 0' zu breit, wenn 'buf.length' nicht Null ist, dann wird read() garantiert mindestens 1 Byte lesen oder -1 zurückgeben (oder eine Exception werfen). –
Was? Gibt 'Process.getInputStream()' einen FileInputStream zurück? –
Ja. In java.lang.ProcessImpl # ProcessImpl können Sie stdout_stream und stderr_stream mit einem FileInputStream initialisieren. Es macht irgendwie Sinn aus der Sicht von Unix, wo alles eine Datei ist. –