无限 100% CPU 使用率在 java.io.FileInputStream.readBytes(本机方法)

2022-09-01 21:29:53

我现在正在调试一个程序,该程序每个外部进程有两个线程,这两个线程继续使用循环读取Process.getErrorStream()和Process.getInputStream()。while ((i = in.read(buf, 0, buf.length)) >= 0)

有时,当外部进程由于JVM崩溃而崩溃时(请参阅这些hs_err_pid.log文件),那些读取该外部进程的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位)上复制了这一点。有问题的代码在这里,它是这样使用的。请参阅这些链接以获取完整代码 - 以下是有趣的部分:

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) {
    ...
}

堆栈跟踪如下所示

"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

使用Sysinternals Process Explorer,我能够获得这些线程的本机堆栈跟踪。大多数情况下,超过 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 的已知问题吗?是否有解决方法?


答案 1

我尚未能够在本地重现此内容,但两种可能的解决方法可能是

  • 玩一玩 .in.available()

  • 将外部进程中的 stoutstderr 重定向到套接字,并改为从控制进程读取此内容。


答案 2

推荐