【问题标题】:JVM not killed on SIGPIPEJVM 没有在 SIGPIPE 上被杀死
【发布时间】:2020-06-30 13:00:38
【问题描述】:

JVM 以这种方式处理 SIGPIPE 的原因是什么?

我会期待

java foo | head -10

public class Foo {
    public static void main(String[] args){
        Stream.iterate(0, n -> n + 1).forEach(System.out::println);
    }
}

在编写第 11 行时导致进程被终止,但事实并非如此。相反,似乎在 PrintStream 上只设置了一个trouble 标志,可以通过System.out.checkError() 进行检查。

【问题讨论】:

    标签: java jvm signals sigpipe


    【解决方案1】:

    发生的情况是 SIGPIPE 异常导致 IOException。

    对于大多数OutputStreamWriter 类,此异常通过“write”方法传播,并且必须由调用者处理。

    但是,当您写入 System.out 时,您使用的是 PrintStream,而该类按设计 会照顾您的 IOException。正如 javadoc 所说:

    PrintStream 向另一个输出流添加了功能,即能够方便地打印各种数据值的表示形式。还提供了另外两个功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;相反,异常情况只是设置一个内部标志,可以通过checkError 方法进行测试。

    JVM 以这种方式处理 SIGPIPE 的原因是什么?

    以上解释了正在发生的事情。 “为什么”是......我猜......设计师想让PrintStream易于使用System.out典型用例,调用者不想处理每次通话都可能出现IOException

    不幸的是,没有优雅的解决方案:

    • 你可以打电话给checkError ...
    • 您应该能够获取FileDescriptor.out 对象,并将其包装在一个新的FileOutputStream 对象中......并使用它来代替System.out

    请注意,不能保证 Java 应用程序只会在 java foo | head -1 中写入 10 行输出。应用程序很可能会提前写入许多行,并且仅在 head 开始阅读其中的前 10 行之后“看到”管道关闭。这适用于System.out(和checkError)或包装FileDescriptor

    【讨论】:

    • 感谢您的回答。这种推理是有道理的。在大多数用例中,每次管道出现问题时处理 IOExceptions 可能会很烦人。如果喜欢这种行为,使用FileDescriptor 的方法似乎是一种优雅的方式。
    • 让我知道它是否有效。我没试过。我通过查看System 类中发生的事情来弄清楚......我可能弄错了。 (我>>认为public。)
    • 当你想写入标准输出时,你需要FileDescriptor.out。一般来说,PrintStream 是一个可怕的错误设计,但与其他 Java 1.0 错误不同,由于在 System.out 字段中的突出位置,它没有被弃用。
    • 似乎是可能的,是的。我想最好将其包装在自定义 PrintStream 中,然后在 IOException 上退出。
    • @leyren PrintStreamOutputStream 的子类型,混淆了字节流和字符流的概念。类似的错误设计的类,例如LineNumberInputStreamStringBufferInputStream 已被弃用。如前所述,PrintStream 没有,尽管有一个替代品 PrintWriter,由于兼容性问题,System.out 无法更改。但即使替换也有吞下异常的可怕行为,只告诉 发生了异常(boolean 值),而不是 which 异常(没有办法得到原来的例外
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    相关资源
    最近更新 更多