Mam teraz debugowanie programu, który ma dwa wątki na jeden proces zewnętrzny, a te dwa wątki wciąż czytają Process.getErrorStream() i Process.getInputStream() przy użyciu pętli while ((i = in.read(buf, 0, buf.length)) >= 0)
.Nieskończone 100% użycie procesora w java.io.FileInputStream.readBytes (metoda macierzysta)
Czasami, gdy proces zewnętrzny ulega awarii z powodu awarii maszyny JVM (patrz these hs_err_pid.log files), wątki odczytujące stdout/stderr z tego zewnętrznego procesu zaczynają zużywać 100% procesora i nigdy nie kończą się. Korpus pętli nie jest wykonywany (Dodałem tam zapis logujący), więc nieskończona pętla wydaje się znajdować w natywnej metodzie java.io.FileInputStream.readBytes
.
Odtworzono to zarówno na 64-bitowym systemie Windows 7 (jdk1.6.0_30 64-bitowy, jdk1.7.0_03 64-bitowy), jak i w systemie Linux 2.6.18 (jdk1.6.0_21 32-bitowy). Kod ten to here i jest używany like this. Zobacz te linki do pełnego kodu - są tu ciekawe bity:
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) {
...
}
Ślady stosu wyglądać
"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
lub
"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
Z Sysinternals Process Explorer udało mi się uzyskać macierzyste ślady stosu tych wątków. Najczęściej, ponad 80% czasu, ślad stosu wygląda następująco:
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
Dzieje się tak również dość często:
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
A czasami to wykonywanie tej części kodu:
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
Jakieś pomysły na rozwiązanie tego problemu? Czy jest to znany problem z JVM? Czy jest w pobliżu praca?
Czy mógłbyś podać swój kod pętli? BTW warunek '> = 0' jest zbyt szeroki, jeśli' buf.length' jest różna od zera, wówczas read() gwarantuje odczyt co najmniej 1 bajtu lub return -1 (lub wyrzucenie wyjątku). –
Co? Czy 'Process.getInputStream()' zwraca FileInputStream? –
Tak. W java.lang.ProcessImpl # ProcessImpl można zobaczyć stdout_stream i stderr_stream zainicjalizowane za pomocą FileInputStream. To ma sens z punktu widzenia Uniksa, gdzie wszystko jest plikiem. –