私は現在、1つの外部プロセスにつき2つのスレッドを持つプログラムをデバッグしています。これらの2つのスレッドはProcess.getErrorStream()およびProcess.getInputStream()while ((i = in.read(buf, 0, buf.length)) >= 0)
ループを使用します。java.io.FileInputStream.readBytes(ネイティブメソッド)の無限100%CPU使用率
JVMクラッシュ(these hs_err_pid.log filesを参照)のために外部プロセスがクラッシュすると、その外部プロセスのstdout/stderrを読み取るスレッドが100%CPUを消費して終了しないことがあります。 ループボディが実行されていません(ここにロギングステートメントが追加されています)、無限ループはネイティブメソッドjava.io.FileInputStream.readBytes
の内部にあるようです。
これは、Windows 7 64ビット(jdk1.6.0_30 64ビット、jdk1.7.0_03 64ビット)とLinux 2.6.18(jdk1.6.0_21 32ビット)の両方でこれを再現しました。問題のコードはhereで、like thisです。完全なコードのためにこれらのリンクを参照してください - ここで興味深いのビットです:
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) {
...
}
スタックトレースは、私がすることができたSysinternalsのプロセスエクスプローラで
"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
または
"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
のように見えますこれらのスレッドのネイティブスタックトレースを取得します。ほとんどの場合、時間の80%を超え、スタックトレースは次のようになります。
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
また、これはかなり頻繁に起こる:
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
そして、時にはそれは、コードのこの部分を実行します:
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
どのようにこの問題を解決するためのアイデアですか?これはJVMの既知の問題ですか?回避策はありますか?
ループコードを含めることができますか? '> = 0'の条件が過度に広い場合、' buf.length'がゼロでない場合、read()は少なくとも1バイトを読み込んだり、-1を返す(またはExceptionをスローする)ことが保証されます。 –
何ですか? 'Process.getInputStream()'はFileInputStreamを返しますか? –
はい。 java.lang.ProcessImpl#ProcessImplでは、stdout_streamとstderr_streamがFileInputStreamで初期化されていることがわかります。すべてがファイルであるUnixの観点からはちょっと意味があります。 –